From 5c4f97cc49bdd615253b3e80e6e5a8f296586f35 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 21 Mar 2024 11:37:11 +0100 Subject: [PATCH 001/236] pkg: fedora: Update to 6.8.1 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 49b950c998..a5db30ff35 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.8.0-63" +PACKAGE_TAG = "kernel-6.8.1-0" ## ## The release number of the modified kernel package. From 50d9c1dc0dfecdbba5214c153f23b6c769456f2b Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Wed, 10 Apr 2024 12:46:05 +0200 Subject: [PATCH 002/236] Remove link to IRC channel The matrix bridge has been dead for a while and won't come back. And personally I never setup an IRC client to join directly. Lets just drop the channel and only use Matrix. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index c5d841493e..929c9d4c6c 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,6 @@ If you have questions or need support, please join our [Matrix Space][matrix-spa This space contains - a [support channel][matrix-support] for general support and - a [development channel][matrix-development] for all development related questions and discussions. - If you prefer IRC, you can also join in via our channel at [`libera.chat/#linux-surface`][liberachat], to which the matrix room is bridged to. ## License This repository contains patches, which are either derivative work targeting a specific already licensed source, i.e. parts of the Linux kernel, or introduce new parts to the Linux kernel. @@ -112,7 +111,6 @@ License texts can be obtained at https://github.com/torvalds/linux/tree/master/L [matrix-space]: https://matrix.to/#/#linux-surface:matrix.org [matrix-support]: https://matrix.to/#/#linux-surface-support:matrix.org [matrix-development]: https://matrix.to/#/#linux-surface-development:matrix.org -[liberachat]: https://web.libera.chat/#linux-surface [hibernate-setup]: https://fitzcarraldoblog.wordpress.com/2018/07/14/configuring-lubuntu-18-04-to-enable-hibernation-using-a-swap-file [releases]: https://github.com/linux-surface/linux-surface/releases From fe8d8fddb43749f084765689a6bf40469c745233 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 16 Apr 2024 13:20:00 +0200 Subject: [PATCH 003/236] Update v6.8 patches Changes: - Update dw9719 fix for Surface Go 2 - Rebased on top of v6.8.6 Links: - kernel: https://github.com/linux-surface/kernel/commit/06142d7649dc1ea02439aed37d3933a34c66368e --- patches/6.8/0012-cameras.patch | 456 +++------------------------------ 1 file changed, 30 insertions(+), 426 deletions(-) diff --git a/patches/6.8/0012-cameras.patch b/patches/6.8/0012-cameras.patch index f18dc443de..9958a34167 100644 --- a/patches/6.8/0012-cameras.patch +++ b/patches/6.8/0012-cameras.patch @@ -699,84 +699,6 @@ index 000000000000..35aeb5db89c8 -- 2.44.0 -From b7e66758c1bd493c7140c17d0f00f727f8fefb32 Mon Sep 17 00:00:00 2001 -From: Hidenori Kobayashi -Date: Tue, 9 Jan 2024 17:09:09 +0900 -Subject: [PATCH] media: staging: ipu3-imgu: Set fields before - media_entity_pads_init() - -The imgu driver fails to probe with the following message because it -does not set the pad's flags before calling media_entity_pads_init(). - -[ 14.596315] ipu3-imgu 0000:00:05.0: failed initialize subdev media entity (-22) -[ 14.596322] ipu3-imgu 0000:00:05.0: failed to register subdev0 ret (-22) -[ 14.596327] ipu3-imgu 0000:00:05.0: failed to register pipes (-22) -[ 14.596331] ipu3-imgu 0000:00:05.0: failed to create V4L2 devices (-22) - -Fix the initialization order so that the driver probe succeeds. The ops -initialization is also moved together for readability. - -Fixes: a0ca1627b450 ("media: staging/intel-ipu3: Add v4l2 driver based on media framework") -Cc: # 6.7 -Cc: Dan Carpenter -Signed-off-by: Hidenori Kobayashi -Signed-off-by: Sakari Ailus -Signed-off-by: Hans Verkuil -Patchset: cameras ---- - drivers/staging/media/ipu3/ipu3-v4l2.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c -index a66f034380c0..3df58eb3e882 100644 ---- a/drivers/staging/media/ipu3/ipu3-v4l2.c -+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c -@@ -1069,6 +1069,11 @@ static int imgu_v4l2_subdev_register(struct imgu_device *imgu, - struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe]; - - /* Initialize subdev media entity */ -+ imgu_sd->subdev.entity.ops = &imgu_media_ops; -+ for (i = 0; i < IMGU_NODE_NUM; i++) { -+ imgu_sd->subdev_pads[i].flags = imgu_pipe->nodes[i].output ? -+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; -+ } - r = media_entity_pads_init(&imgu_sd->subdev.entity, IMGU_NODE_NUM, - imgu_sd->subdev_pads); - if (r) { -@@ -1076,11 +1081,6 @@ static int imgu_v4l2_subdev_register(struct imgu_device *imgu, - "failed initialize subdev media entity (%d)\n", r); - return r; - } -- imgu_sd->subdev.entity.ops = &imgu_media_ops; -- for (i = 0; i < IMGU_NODE_NUM; i++) { -- imgu_sd->subdev_pads[i].flags = imgu_pipe->nodes[i].output ? -- MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; -- } - - /* Initialize subdev */ - v4l2_subdev_init(&imgu_sd->subdev, &imgu_subdev_ops); -@@ -1177,15 +1177,15 @@ static int imgu_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe, - } - - /* Initialize media entities */ -+ node->vdev_pad.flags = node->output ? -+ MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; -+ vdev->entity.ops = NULL; - r = media_entity_pads_init(&vdev->entity, 1, &node->vdev_pad); - if (r) { - dev_err(dev, "failed initialize media entity (%d)\n", r); - mutex_destroy(&node->lock); - return r; - } -- node->vdev_pad.flags = node->output ? -- MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; -- vdev->entity.ops = NULL; - - /* Initialize vbq */ - vbq->type = node->vdev_fmt.type; --- -2.44.0 - From 87ebc160cb35a068acfaf59847c84656cb52b1b7 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 25 May 2023 14:12:04 +0300 @@ -851,354 +773,6 @@ index ed08bf4178f0..83e29c56fe33 100644 -- 2.44.0 -From a9681c29588d67321733877e11f9588ed9e54861 Mon Sep 17 00:00:00 2001 -From: mojyack -Date: Sat, 3 Feb 2024 12:53:33 +0900 -Subject: [PATCH] media: i2c: Revert DW9719 driver - -Patchset: cameras ---- - drivers/media/i2c/dw9719.c | 199 +++++++++++++++++++++++++------------ - 1 file changed, 137 insertions(+), 62 deletions(-) - -diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..d5f585dabb60 100644 ---- a/drivers/media/i2c/dw9719.c -+++ b/drivers/media/i2c/dw9719.c -@@ -6,13 +6,14 @@ - * https://github.com/ZenfoneArea/android_kernel_asus_zenfone5 - */ - -+#include -+ - #include - #include - #include - #include - #include - --#include - #include - #include - #include -@@ -20,31 +21,29 @@ - #define DW9719_MAX_FOCUS_POS 1023 - #define DW9719_CTRL_STEPS 16 - #define DW9719_CTRL_DELAY_US 1000 -+#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) - --#define DW9719_INFO CCI_REG8(0) -+#define DW9719_INFO 0 - #define DW9719_ID 0xF1 -+#define DW9719_CONTROL 2 -+#define DW9719_VCM_CURRENT 3 - --#define DW9719_CONTROL CCI_REG8(2) --#define DW9719_ENABLE_RINGING 0x02 -- --#define DW9719_VCM_CURRENT CCI_REG16(3) -- --#define DW9719_MODE CCI_REG8(6) --#define DW9719_MODE_SAC_SHIFT 4 --#define DW9719_MODE_SAC3 4 -+#define DW9719_MODE 6 -+#define DW9719_VCM_FREQ 7 - --#define DW9719_VCM_FREQ CCI_REG8(7) -+#define DW9719_MODE_SAC3 0x40 - #define DW9719_DEFAULT_VCM_FREQ 0x60 -+#define DW9719_ENABLE_RINGING 0x02 -+ -+#define NUM_REGULATORS 2 - - #define to_dw9719_device(x) container_of(x, struct dw9719_device, sd) - - struct dw9719_device { -- struct v4l2_subdev sd; - struct device *dev; -- struct regmap *regmap; -- struct regulator *regulator; -- u32 sac_mode; -- u32 vcm_freq; -+ struct i2c_client *client; -+ struct regulator_bulk_data regulators[NUM_REGULATORS]; -+ struct v4l2_subdev sd; - - struct dw9719_v4l2_ctrls { - struct v4l2_ctrl_handler handler; -@@ -52,18 +51,79 @@ struct dw9719_device { - } ctrls; - }; - -+static int dw9719_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val) -+{ -+ struct i2c_msg msg[2]; -+ u8 buf[2] = { reg }; -+ int ret; -+ -+ msg[0].addr = client->addr; -+ msg[0].flags = 0; -+ msg[0].len = 1; -+ msg[0].buf = buf; -+ -+ msg[1].addr = client->addr; -+ msg[1].flags = I2C_M_RD; -+ msg[1].len = 1; -+ msg[1].buf = &buf[1]; -+ *val = 0; -+ -+ ret = i2c_transfer(client->adapter, msg, 2); -+ if (ret < 0) -+ return ret; -+ -+ *val = buf[1]; -+ -+ return 0; -+} -+ -+static int dw9719_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -+{ -+ struct i2c_msg msg; -+ int ret; -+ -+ u8 buf[2] = { reg, val }; -+ -+ msg.addr = client->addr; -+ msg.flags = 0; -+ msg.len = sizeof(buf); -+ msg.buf = buf; -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ -+ return ret < 0 ? ret : 0; -+} -+ -+static int dw9719_i2c_wr16(struct i2c_client *client, u8 reg, u16 val) -+{ -+ struct i2c_msg msg; -+ u8 buf[3] = { reg }; -+ int ret; -+ -+ put_unaligned_be16(val, buf + 1); -+ -+ msg.addr = client->addr; -+ msg.flags = 0; -+ msg.len = sizeof(buf); -+ msg.buf = buf; -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ -+ return ret < 0 ? ret : 0; -+} -+ - static int dw9719_detect(struct dw9719_device *dw9719) - { - int ret; -- u64 val; -+ u8 val; - -- ret = cci_read(dw9719->regmap, DW9719_INFO, &val, NULL); -+ ret = dw9719_i2c_rd8(dw9719->client, DW9719_INFO, &val); - if (ret < 0) - return ret; - - if (val != DW9719_ID) { - dev_err(dw9719->dev, "Failed to detect correct id\n"); -- return -ENXIO; -+ ret = -ENXIO; - } - - return 0; -@@ -71,37 +131,54 @@ static int dw9719_detect(struct dw9719_device *dw9719) - - static int dw9719_power_down(struct dw9719_device *dw9719) - { -- return regulator_disable(dw9719->regulator); -+ return regulator_bulk_disable(NUM_REGULATORS, dw9719->regulators); - } - - static int dw9719_power_up(struct dw9719_device *dw9719) - { - int ret; - -- ret = regulator_enable(dw9719->regulator); -+ ret = regulator_bulk_enable(NUM_REGULATORS, dw9719->regulators); - if (ret) - return ret; - - /* Jiggle SCL pin to wake up device */ -- cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_CONTROL, 1); - -- /* Need 100us to transit from SHUTDOWN to STANDBY */ -- fsleep(100); -+ /* Need 100us to transit from SHUTDOWN to STANDBY*/ -+ usleep_range(100, 1000); - -- cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret); -- cci_write(dw9719->regmap, DW9719_MODE, -- dw9719->sac_mode << DW9719_MODE_SAC_SHIFT, &ret); -- cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret); -+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_CONTROL, -+ DW9719_ENABLE_RINGING); -+ if (ret < 0) -+ goto fail_powerdown; - -- if (ret) -- dw9719_power_down(dw9719); -+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_MODE, DW9719_MODE_SAC3); -+ if (ret < 0) -+ goto fail_powerdown; -+ -+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_VCM_FREQ, -+ DW9719_DEFAULT_VCM_FREQ); -+ if (ret < 0) -+ goto fail_powerdown; -+ -+ return 0; - -+fail_powerdown: -+ dw9719_power_down(dw9719); - return ret; - } - - static int dw9719_t_focus_abs(struct dw9719_device *dw9719, s32 value) - { -- return cci_write(dw9719->regmap, DW9719_VCM_CURRENT, value, NULL); -+ int ret; -+ -+ value = clamp(value, 0, DW9719_MAX_FOCUS_POS); -+ ret = dw9719_i2c_wr16(dw9719->client, DW9719_VCM_CURRENT, value); -+ if (ret < 0) -+ return ret; -+ -+ return 0; - } - - static int dw9719_set_ctrl(struct v4l2_ctrl *ctrl) -@@ -132,7 +209,7 @@ static const struct v4l2_ctrl_ops dw9719_ctrl_ops = { - .s_ctrl = dw9719_set_ctrl, - }; - --static int dw9719_suspend(struct device *dev) -+static int __maybe_unused dw9719_suspend(struct device *dev) - { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct dw9719_device *dw9719 = to_dw9719_device(sd); -@@ -151,7 +228,7 @@ static int dw9719_suspend(struct device *dev) - return dw9719_power_down(dw9719); - } - --static int dw9719_resume(struct device *dev) -+static int __maybe_unused dw9719_resume(struct device *dev) - { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct dw9719_device *dw9719 = to_dw9719_device(sd); -@@ -201,7 +278,9 @@ static int dw9719_init_controls(struct dw9719_device *dw9719) - const struct v4l2_ctrl_ops *ops = &dw9719_ctrl_ops; - int ret; - -- v4l2_ctrl_handler_init(&dw9719->ctrls.handler, 1); -+ ret = v4l2_ctrl_handler_init(&dw9719->ctrls.handler, 1); -+ if (ret) -+ return ret; - - dw9719->ctrls.focus = v4l2_ctrl_new_std(&dw9719->ctrls.handler, ops, - V4L2_CID_FOCUS_ABSOLUTE, 0, -@@ -214,7 +293,8 @@ static int dw9719_init_controls(struct dw9719_device *dw9719) - } - - dw9719->sd.ctrl_handler = &dw9719->ctrls.handler; -- return 0; -+ -+ return ret; - - err_free_handler: - v4l2_ctrl_handler_free(&dw9719->ctrls.handler); -@@ -232,26 +312,24 @@ static int dw9719_probe(struct i2c_client *client) - if (!dw9719) - return -ENOMEM; - -- dw9719->regmap = devm_cci_regmap_init_i2c(client, 8); -- if (IS_ERR(dw9719->regmap)) -- return PTR_ERR(dw9719->regmap); -- -+ dw9719->client = client; - dw9719->dev = &client->dev; -- dw9719->sac_mode = DW9719_MODE_SAC3; -- dw9719->vcm_freq = DW9719_DEFAULT_VCM_FREQ; - -- /* Optional indication of SAC mode select */ -- device_property_read_u32(&client->dev, "dongwoon,sac-mode", -- &dw9719->sac_mode); -- -- /* Optional indication of VCM frequency */ -- device_property_read_u32(&client->dev, "dongwoon,vcm-freq", -- &dw9719->vcm_freq); -+ dw9719->regulators[0].supply = "vdd"; -+ /* -+ * The DW9719 has only the 1 VDD voltage input, but some PMICs such as -+ * the TPS68470 PMIC have I2C passthrough capability, to disconnect the -+ * sensor's I2C pins from the I2C bus when the sensors VSIO (Sensor-IO) -+ * is off, because some sensors then short these pins to ground; -+ * and the DW9719 might sit behind this passthrough, this it needs to -+ * enable VSIO as that will also enable the I2C passthrough. -+ */ -+ dw9719->regulators[1].supply = "vsio"; - -- dw9719->regulator = devm_regulator_get(&client->dev, "vdd"); -- if (IS_ERR(dw9719->regulator)) -- return dev_err_probe(&client->dev, PTR_ERR(dw9719->regulator), -- "getting regulator\n"); -+ ret = devm_regulator_bulk_get(&client->dev, NUM_REGULATORS, -+ dw9719->regulators); -+ if (ret) -+ return dev_err_probe(&client->dev, ret, "getting regulators\n"); - - v4l2_i2c_subdev_init(&dw9719->sd, client, &dw9719_ops); - dw9719->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -@@ -312,17 +390,13 @@ static int dw9719_probe(struct i2c_client *client) - static void dw9719_remove(struct i2c_client *client) - { - struct v4l2_subdev *sd = i2c_get_clientdata(client); -- struct dw9719_device *dw9719 = -- container_of(sd, struct dw9719_device, sd); -+ struct dw9719_device *dw9719 = container_of(sd, struct dw9719_device, -+ sd); - -+ pm_runtime_disable(&client->dev); - v4l2_async_unregister_subdev(sd); - v4l2_ctrl_handler_free(&dw9719->ctrls.handler); - media_entity_cleanup(&dw9719->sd.entity); -- -- pm_runtime_disable(&client->dev); -- if (!pm_runtime_status_suspended(&client->dev)) -- dw9719_power_down(dw9719); -- pm_runtime_set_suspended(&client->dev); - } - - static const struct i2c_device_id dw9719_id_table[] = { -@@ -331,13 +405,14 @@ static const struct i2c_device_id dw9719_id_table[] = { - }; - MODULE_DEVICE_TABLE(i2c, dw9719_id_table); - --static DEFINE_RUNTIME_DEV_PM_OPS(dw9719_pm_ops, dw9719_suspend, dw9719_resume, -- NULL); -+static const struct dev_pm_ops dw9719_pm_ops = { -+ SET_RUNTIME_PM_OPS(dw9719_suspend, dw9719_resume, NULL) -+}; - - static struct i2c_driver dw9719_i2c_driver = { - .driver = { - .name = "dw9719", -- .pm = pm_sleep_ptr(&dw9719_pm_ops), -+ .pm = &dw9719_pm_ops, - }, - .probe = dw9719_probe, - .remove = dw9719_remove, --- -2.44.0 - From c5d6c95fd5cefbd4ba9779fc965bce0a36bdbe5e Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 @@ -1246,3 +820,33 @@ index 3df58eb3e882..81aff2d5d898 100644 -- 2.44.0 +From 65421dfc17e3559d45345ea2aa48b44268653496 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.44.0 + From 3ef102d59791774f144dd4df4b608974fc41bef0 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 16 Apr 2024 13:25:34 +0200 Subject: [PATCH 004/236] pkg: arch: Update to 6.8.6 --- pkg/arch/kernel/PKGBUILD | 8 ++++---- pkg/arch/kernel/config | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 4202895cfd..1aa81444cf 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.8.1.arch1 +pkgver=6.8.6.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -56,8 +56,8 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('SKIP' - 'c2b00c84c4b543db431e06604d939a62f93107d18369f4d9860dc8062b01ab45' +sha256sums=('2a56b8533af53cf5d3be8882a4a2da34a8d5a2d26569b098102aa072960c32e0' + '9a21f27cdfdb1d7b27af526b2c85632eca890e5264cd44dcb0882e9953794a2a' '985cd5e0b11538f31887e451c398d226c06ca4b34c5466e93a21ebd65b7b3919' '3cabe391cc39dbee88a79f76e9e7a68f7fbcd5518941aa2ab73a77692c87dead' 'ee9857e96ee5d871aa557f6d6d142474c26187faa2c21b351bafde065b288fe0' @@ -71,7 +71,7 @@ sha256sums=('SKIP' '02d720e3fffae018fc8719a98135e63c84e8b7f39769bcdee45ddf973a567732' '6225348b31112a67f5e37a9075363b36c103ba6144083cf4e2d7d83edc77513c' 'ea0016af33f682a0353738b00c39407b7e1a96a9ccfb04b3904b58143c1953ee' - '19fb55efe921ac95376ec2169b09add1846aa3bdf9eff368d74f2cc1f25364d5' + 'f59a6c1a59699664eeeb5243cb961845944cbc6d1c63353ad9d2ff7d8b593ec3' '1e620fa5bb90d7a8d4a57d0dc1552b096762a4da4cf1a5ce461d54c3c9b9885f' '7693cf1df35a47ec8702543d9665f9010a5c7db18a39d9506649e892fd36954f') diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index 4d684210b9..9cc6c3620b 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.8.1-arch1 Kernel Configuration +# Linux/x86 6.8.6-arch1 Kernel Configuration # CONFIG_CC_VERSION_TEXT="gcc (GCC) 13.2.1 20230801" CONFIG_CC_IS_GCC=y @@ -471,7 +471,6 @@ CONFIG_X86_DIRECT_GBPAGES=y CONFIG_X86_CPA_STATISTICS=y CONFIG_X86_MEM_ENCRYPT=y CONFIG_AMD_MEM_ENCRYPT=y -# CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT is not set CONFIG_NUMA=y CONFIG_AMD_NUMA=y CONFIG_X86_64_ACPI_NUMA=y @@ -567,6 +566,9 @@ CONFIG_CPU_SRSO=y CONFIG_SLS=y # CONFIG_GDS_FORCE_MITIGATION is not set CONFIG_MITIGATION_RFDS=y +CONFIG_SPECTRE_BHI_ON=y +# CONFIG_SPECTRE_BHI_OFF is not set +# CONFIG_SPECTRE_BHI_AUTO is not set CONFIG_ARCH_HAS_ADD_PAGES=y # @@ -964,6 +966,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_MODULE_SIG=y # CONFIG_MODULE_SIG_FORCE is not set CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set # CONFIG_MODULE_SIG_SHA256 is not set # CONFIG_MODULE_SIG_SHA384 is not set CONFIG_MODULE_SIG_SHA512=y @@ -1999,7 +2002,6 @@ CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_CMTP=m CONFIG_BT_HIDP=m -# CONFIG_BT_HS is not set CONFIG_BT_LE=y CONFIG_BT_LE_L2CAP_ECRED=y CONFIG_BT_6LOWPAN=m From 57fe2f4f4045f1959f8bd44d798080605e14e612 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 16 Apr 2024 13:26:03 +0200 Subject: [PATCH 005/236] pkg: debian: Update to 6.8.6 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 36b476aca3..5a3cb79058 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.8.1" +KERNEL_VERSION="6.8.6" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 44d15ab270086aa8f2672ecbe7cd741519c21657 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 16 Apr 2024 13:27:06 +0200 Subject: [PATCH 006/236] pkg: fedora: Update to 6.8.6 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index a5db30ff35..97d9493d45 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.8.1-0" +PACKAGE_TAG = "kernel-6.8.6-0" ## ## The release number of the modified kernel package. From e5c2f49c1e5c8eb661c3af71c898067e5258ffad Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 21 Apr 2024 13:43:24 +0200 Subject: [PATCH 007/236] pkg/arch: Build-in pinctrl and serial drivers --- pkg/arch/kernel/arch.config | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pkg/arch/kernel/arch.config b/pkg/arch/kernel/arch.config index e18e444ab7..4580db09ee 100644 --- a/pkg/arch/kernel/arch.config +++ b/pkg/arch/kernel/arch.config @@ -24,3 +24,20 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_ANDROID_BINDERFS=y CONFIG_ANDROID_BINDER_DEVICES="" + +## +## Build-in basic pinctrl/serial modules to prevent race-conditions in drivers +## relying on them (like soc-button-array, SAM) +## + +CONFIG_SERIAL_8250_DW=y +CONFIG_MFD_INTEL_LPSS=y +CONFIG_MFD_INTEL_LPSS_PCI=y + +CONFIG_PINCTRL_INTEL=y +CONFIG_PINCTRL_ALDERLAKE=y +CONFIG_PINCTRL_CANNONLAKE=y +CONFIG_PINCTRL_ICELAKE=y +CONFIG_PINCTRL_METEORLAKE=y +CONFIG_PINCTRL_SUNRISEPOINT=y +CONFIG_PINCTRL_TIGERLAKE=y From 03cfcbc7c266acd7f5e1a8ab496e98733298426a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Apr 2024 09:38:10 +0200 Subject: [PATCH 008/236] Update v6.8 patches Changes: - Fixed IPTS not compiling with -Werror enabled (@jasisonee) - Added QuickSPI support to ITHC for Surface Laptop Studio 2 (@quo) Links: - kernel: https://github.com/linux-surface/kernel/commit/63781a056a0f06d5cc38d7755e0753c7ec08c51c --- patches/6.8/0004-ipts.patch | 53 + patches/6.8/0005-ithc.patch | 2520 ++++++++++++++++++++++++++++ patches/6.8/0006-surface-sam.patch | 54 + 3 files changed, 2627 insertions(+) diff --git a/patches/6.8/0004-ipts.patch b/patches/6.8/0004-ipts.patch index 383a872937..bab19d1d3c 100644 --- a/patches/6.8/0004-ipts.patch +++ b/patches/6.8/0004-ipts.patch @@ -3236,3 +3236,56 @@ index 000000000000..1f966b8b32c4 -- 2.44.0 +From e5b4ea8a015bee22023bb5c8fb6dd8b708bff7d5 Mon Sep 17 00:00:00 2001 +From: Jasmin Huber +Date: Mon, 15 Apr 2024 10:22:55 +0200 +Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile + with -Wmissing-prototypes. + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/ipts/eds1.c | 1 + + drivers/hid/ipts/eds2.c | 1 + + drivers/hid/ipts/receiver.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +index ecbb3a8bdaf6..7b9f54388a9f 100644 +--- a/drivers/hid/ipts/eds1.c ++++ b/drivers/hid/ipts/eds1.c +@@ -14,6 +14,7 @@ + #include "context.h" + #include "control.h" + #include "desc.h" ++#include "eds1.h" + #include "spec-device.h" + + int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +index 198dc65d7887..639940794615 100644 +--- a/drivers/hid/ipts/eds2.c ++++ b/drivers/hid/ipts/eds2.c +@@ -15,6 +15,7 @@ + #include "context.h" + #include "control.h" + #include "desc.h" ++#include "eds2.h" + #include "spec-data.h" + + int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +index ef66c3c9db80..977724c728c3 100644 +--- a/drivers/hid/ipts/receiver.c ++++ b/drivers/hid/ipts/receiver.c +@@ -16,6 +16,7 @@ + #include "context.h" + #include "control.h" + #include "hid.h" ++#include "receiver.h" + #include "resources.h" + #include "spec-device.h" + #include "thread.h" +-- +2.44.0 + diff --git a/patches/6.8/0005-ithc.patch b/patches/6.8/0005-ithc.patch index 38aaadbce2..f9722e9c01 100644 --- a/patches/6.8/0005-ithc.patch +++ b/patches/6.8/0005-ithc.patch @@ -1818,3 +1818,2523 @@ index 000000000000..028e55a4ec53 -- 2.44.0 +From 62697b8742afc950b55ed24d8ef2fca5834426b6 Mon Sep 17 00:00:00 2001 +From: quo +Date: Fri, 19 Apr 2024 22:11:09 +0200 +Subject: [PATCH] hid: ithc: Update from quo/ithc-linux + + - Added QuickSPI support for Surface Laptop Studio 2 + - Use Latency Tolerance Reporting instead of manual CPU latency adjustments + +Based on: https://github.com/quo/ithc-linux/commit/18afc6ffacd70b49fdee2eb1ab0a8acd159edb31 + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/hid/ithc/Kbuild | 2 +- + drivers/hid/ithc/ithc-debug.c | 33 +- + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 125 ++----- + drivers/hid/ithc/ithc-dma.h | 24 +- + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 252 ++++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 386 ++++----------------- + drivers/hid/ithc/ithc-quickspi.c | 578 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 +++ + drivers/hid/ithc/ithc-regs.c | 72 +++- + drivers/hid/ithc/ithc-regs.h | 143 ++++---- + drivers/hid/ithc/ithc.h | 71 ++-- + 15 files changed, 1441 insertions(+), 538 deletions(-) + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +index aea83f2ac07b..4937ba131297 100644 +--- a/drivers/hid/ithc/Kbuild ++++ b/drivers/hid/ithc/Kbuild +@@ -1,6 +1,6 @@ + obj-$(CONFIG_HID_ITHC) := ithc.o + +-ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-debug.o ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o + + ccflags-y := -std=gnu11 -Wno-declaration-after-statement + +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +index 1f1f1e33f2e5..2d8c6afe9966 100644 +--- a/drivers/hid/ithc/ithc-debug.c ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -85,10 +85,11 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si + case 'd': // dma command: cmd len data... + // get report descriptor: d 7 8 0 0 + // enable multitouch: d 3 2 0x0105 +- if (n < 2 || a[1] > (n - 2) * 4) ++ if (n < 1) + return -EINVAL; +- pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]); +- if (ithc_dma_tx(ithc, a[0], a[1], a + 2)) ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) + pci_err(ithc->pci, "dma tx failed\n"); + break; + default: +@@ -98,6 +99,23 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si + return len; + } + ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ + static const struct file_operations ithc_debugfops_cmd = { + .owner = THIS_MODULE, + .write = ithc_debugfs_cmd_write, +@@ -106,17 +124,18 @@ static const struct file_operations ithc_debugfops_cmd = { + static void ithc_debugfs_devres_release(struct device *dev, void *res) + { + struct dentry **dbgm = res; +- if (*dbgm) +- debugfs_remove_recursive(*dbgm); ++ debugfs_remove_recursive(*dbgm); + } + +-int ithc_debug_init(struct ithc *ithc) ++int ithc_debug_init_device(struct ithc *ithc) + { ++ if (!dbg_dir) ++ return -ENOENT; + struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); + if (!dbgm) + return -ENOMEM; + devres_add(&ithc->pci->dev, dbgm); +- struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); + if (IS_ERR(dbg)) + return PTR_ERR(dbg); + *dbgm = dbg; +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +index ffb8689b8a78..bf4eab33062b 100644 +--- a/drivers/hid/ithc/ithc-dma.c ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -173,10 +173,9 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel) + mutex_init(&rx->mutex); + + // Allocate buffers. +- u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes); +- unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; + pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", +- NUM_RX_BUF, buf_size, num_pages); ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); + CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); + for (unsigned int i = 0; i < NUM_RX_BUF; i++) + CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); +@@ -214,10 +213,9 @@ int ithc_dma_tx_init(struct ithc *ithc) + mutex_init(&tx->mutex); + + // Allocate buffers. +- tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes); +- unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; + pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", +- tx->max_size, num_pages); ++ ithc->max_tx_size, num_pages); + CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); + CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); + +@@ -230,71 +228,6 @@ int ithc_dma_tx_init(struct ithc *ithc) + return 0; + } + +-static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data, +- u8 channel, u8 buf) +-{ +- if (buf >= NUM_RX_BUF) { +- pci_err(ithc->pci, "invalid dma ringbuffer index\n"); +- return -EINVAL; +- } +- u32 len = data->data_size; +- struct ithc_dma_rx_header *hdr = data->addr; +- u8 *hiddata = (void *)(hdr + 1); +- if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) { +- // The THC sends a reset request when we need to reinitialize the device. +- // This usually only happens if we send an invalid command or put the device +- // in a bad state. +- CHECK(ithc_reset, ithc); +- } else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) { +- if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { +- // When the CPU enters a low power state during DMA, we can get truncated +- // messages. For Surface devices, this will typically be a single touch +- // report that is only 1 byte, or a multitouch report that is 257 bytes. +- // See also ithc_set_active(). +- } else { +- pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n", +- channel, buf, len, hdr->code, hdr->data_size); +- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, +- hdr, min(len, 0x400u), 0); +- } +- } else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) { +- // Response to a 'get report descriptor' request. +- // The actual descriptor is preceded by 8 nul bytes. +- CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8); +- WRITE_ONCE(ithc->hid_parse_done, true); +- wake_up(&ithc->wait_hid_parse); +- } else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { +- // Standard HID input report containing touch data. +- CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1); +- } else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) { +- // Response to a 'get feature' request. +- bool done = false; +- mutex_lock(&ithc->hid_get_feature_mutex); +- if (ithc->hid_get_feature_buf) { +- if (hdr->data_size < ithc->hid_get_feature_size) +- ithc->hid_get_feature_size = hdr->data_size; +- memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size); +- ithc->hid_get_feature_buf = NULL; +- done = true; +- } +- mutex_unlock(&ithc->hid_get_feature_mutex); +- if (done) { +- wake_up(&ithc->wait_hid_get_feature); +- } else { +- // Received data without a matching request, or the request already +- // timed out. (XXX What's the correct thing to do here?) +- CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT, +- hiddata, hdr->data_size, 1); +- } +- } else { +- pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n", +- channel, buf, len, hdr->code); +- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, +- hdr, min(len, 0x400u), 0); +- } +- return 0; +-} +- + static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) + { + // Process all filled RX buffers from the ringbuffer. +@@ -316,7 +249,16 @@ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) + rx->num_received = ++n; + + // process data +- CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail); ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } + + // give the buffer back to the device + CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); +@@ -331,31 +273,28 @@ int ithc_dma_rx(struct ithc *ithc, u8 channel) + return ret; + } + +-static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) + { +- ithc_set_active(ithc, 100 * USEC_PER_MSEC); +- + // Send a single TX buffer to the THC. +- pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize); +- struct ithc_dma_tx_header *hdr; +- // Data must be padded to next 4-byte boundary. +- u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0; +- unsigned int fullsize = sizeof(*hdr) + datasize + padding; +- if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE) +- return -EINVAL; ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); + CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); + + // Fill the TX buffer with header and data. +- ithc->dma_tx.buf.data_size = fullsize; +- hdr = ithc->dma_tx.buf.addr; +- hdr->code = cmdcode; +- hdr->data_size = datasize; +- u8 *dest = (void *)(hdr + 1); +- memcpy(dest, data, datasize); +- dest += datasize; +- for (u8 p = 0; p < padding; p++) +- *dest++ = 0; ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; + CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } + + // Let the THC process the buffer. + bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); +@@ -363,10 +302,10 @@ static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, vo + writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); + return 0; + } +-int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) + { + mutex_lock(&ithc->dma_tx.mutex); +- int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data); ++ int ret = ithc_dma_tx_unlocked(ithc, data); + mutex_unlock(&ithc->dma_tx.mutex); + return ret; + } +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +index 93652e4476bf..1749a5819b3e 100644 +--- a/drivers/hid/ithc/ithc-dma.h ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -11,27 +11,6 @@ struct ithc_phys_region_desc { + u32 unused; + }; + +-#define DMA_RX_CODE_INPUT_REPORT 3 +-#define DMA_RX_CODE_FEATURE_REPORT 4 +-#define DMA_RX_CODE_REPORT_DESCRIPTOR 5 +-#define DMA_RX_CODE_RESET 7 +- +-struct ithc_dma_rx_header { +- u32 code; +- u32 data_size; +- u32 _unknown[14]; +-}; +- +-#define DMA_TX_CODE_SET_FEATURE 3 +-#define DMA_TX_CODE_GET_FEATURE 4 +-#define DMA_TX_CODE_OUTPUT_REPORT 5 +-#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7 +- +-struct ithc_dma_tx_header { +- u32 code; +- u32 data_size; +-}; +- + struct ithc_dma_prd_buffer { + void *addr; + dma_addr_t dma_addr; +@@ -49,7 +28,6 @@ struct ithc_dma_data_buffer { + + struct ithc_dma_tx { + struct mutex mutex; +- u32 max_size; + struct ithc_dma_prd_buffer prds; + struct ithc_dma_data_buffer buf; + }; +@@ -65,5 +43,5 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel); + void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); + int ithc_dma_tx_init(struct ithc *ithc); + int ithc_dma_rx(struct ithc *ithc, u8 channel); +-int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); + +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..5c1da11e3f1d +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,252 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on some ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +index 87ed4aa70fda..2acf02e41d40 100644 +--- a/drivers/hid/ithc/ithc-main.c ++++ b/drivers/hid/ithc/ithc-main.c +@@ -5,28 +5,6 @@ + MODULE_DESCRIPTION("Intel Touch Host Controller driver"); + MODULE_LICENSE("Dual BSD/GPL"); + +-// Lakefield +-#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 +-#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 +-// Tiger Lake +-#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 +-#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 +-#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 +-#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 +-// Alder Lake +-#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 +-// Raptor Lake +-#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 +-#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 +-// Meteor Lake +-#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 +-#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a +- + static const struct pci_device_id ithc_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, +@@ -66,15 +44,13 @@ static bool ithc_use_rx1 = true; + module_param_named(rx1, ithc_use_rx1, bool, 0); + MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); + +-// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering. +-static int ithc_dma_latency_us = 200; +-module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0); +-MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS"); ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); + +-// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering. +-static unsigned int ithc_dma_early_us = 2000; +-module_param_named(dma_early_us, ithc_dma_early_us, uint, 0); +-MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)"); ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); + + static bool ithc_log_regs_enabled = false; + module_param_named(logregs, ithc_log_regs_enabled, bool, 0); +@@ -82,44 +58,30 @@ MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); + + // Sysfs attributes + +-static bool ithc_is_config_valid(struct ithc *ithc) +-{ +- return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC; +-} +- + static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc_is_config_valid(ithc)) ++ if (!ithc || !ithc->have_config) + return -ENODEV; +- return sprintf(buf, "0x%04x", ithc->config.vendor_id); ++ return sprintf(buf, "0x%04x", ithc->vendor_id); + } + static DEVICE_ATTR_RO(vendor); + static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc_is_config_valid(ithc)) ++ if (!ithc || !ithc->have_config) + return -ENODEV; +- return sprintf(buf, "0x%04x", ithc->config.product_id); ++ return sprintf(buf, "0x%04x", ithc->product_id); + } + static DEVICE_ATTR_RO(product); + static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc_is_config_valid(ithc)) ++ if (!ithc || !ithc->have_config) + return -ENODEV; +- return sprintf(buf, "%u", ithc->config.revision); ++ return sprintf(buf, "%u", ithc->product_rev); + } + static DEVICE_ATTR_RO(revision); +-static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc_is_config_valid(ithc)) +- return -ENODEV; +- u32 v = ithc->config.fw_version; +- return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff); +-} +-static DEVICE_ATTR_RO(fw_version); + + static const struct attribute_group *ithc_attribute_groups[] = { + &(const struct attribute_group){ +@@ -128,185 +90,26 @@ static const struct attribute_group *ithc_attribute_groups[] = { + &dev_attr_vendor.attr, + &dev_attr_product.attr, + &dev_attr_revision.attr, +- &dev_attr_fw_version.attr, + NULL + }, + }, + NULL + }; + +-// HID setup +- +-static int ithc_hid_start(struct hid_device *hdev) { return 0; } +-static void ithc_hid_stop(struct hid_device *hdev) { } +-static int ithc_hid_open(struct hid_device *hdev) { return 0; } +-static void ithc_hid_close(struct hid_device *hdev) { } +- +-static int ithc_hid_parse(struct hid_device *hdev) +-{ +- struct ithc *ithc = hdev->driver_data; +- u64 val = 0; +- WRITE_ONCE(ithc->hid_parse_done, false); +- for (int retries = 0; ; retries++) { +- CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val); +- if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done), +- msecs_to_jiffies(200))) +- return 0; +- if (retries > 5) { +- pci_err(ithc->pci, "failed to read report descriptor\n"); +- return -ETIMEDOUT; +- } +- pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); +- } +-} +- +-static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, +- size_t len, unsigned char rtype, int reqtype) +-{ +- struct ithc *ithc = hdev->driver_data; +- if (!buf || !len) +- return -EINVAL; +- u32 code; +- if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { +- code = DMA_TX_CODE_OUTPUT_REPORT; +- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { +- code = DMA_TX_CODE_SET_FEATURE; +- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { +- code = DMA_TX_CODE_GET_FEATURE; +- } else { +- pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", +- rtype, reqtype, reportnum); +- return -EINVAL; +- } +- buf[0] = reportnum; +- +- if (reqtype == HID_REQ_GET_REPORT) { +- // Prepare for response. +- mutex_lock(&ithc->hid_get_feature_mutex); +- ithc->hid_get_feature_buf = buf; +- ithc->hid_get_feature_size = len; +- mutex_unlock(&ithc->hid_get_feature_mutex); +- +- // Transmit 'get feature' request. +- int r = CHECK(ithc_dma_tx, ithc, code, 1, buf); +- if (!r) { +- r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature, +- !ithc->hid_get_feature_buf, msecs_to_jiffies(1000)); +- if (!r) +- r = -ETIMEDOUT; +- else if (r < 0) +- r = -EINTR; +- else +- r = 0; +- } +- +- // If everything went ok, the buffer has been filled with the response data. +- // Return the response size. +- mutex_lock(&ithc->hid_get_feature_mutex); +- ithc->hid_get_feature_buf = NULL; +- if (!r) +- r = ithc->hid_get_feature_size; +- mutex_unlock(&ithc->hid_get_feature_mutex); +- return r; +- } +- +- // 'Set feature', or 'output report'. These don't have a response. +- CHECK_RET(ithc_dma_tx, ithc, code, len, buf); +- return 0; +-} +- +-static struct hid_ll_driver ithc_ll_driver = { +- .start = ithc_hid_start, +- .stop = ithc_hid_stop, +- .open = ithc_hid_open, +- .close = ithc_hid_close, +- .parse = ithc_hid_parse, +- .raw_request = ithc_hid_raw_request, +-}; +- +-static void ithc_hid_devres_release(struct device *dev, void *res) +-{ +- struct hid_device **hidm = res; +- if (*hidm) +- hid_destroy_device(*hidm); +-} +- +-static int ithc_hid_init(struct ithc *ithc) +-{ +- struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); +- if (!hidm) +- return -ENOMEM; +- devres_add(&ithc->pci->dev, hidm); +- struct hid_device *hid = hid_allocate_device(); +- if (IS_ERR(hid)) +- return PTR_ERR(hid); +- *hidm = hid; +- +- strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); +- strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); +- hid->ll_driver = &ithc_ll_driver; +- hid->bus = BUS_PCI; +- hid->vendor = ithc->config.vendor_id; +- hid->product = ithc->config.product_id; +- hid->version = 0x100; +- hid->dev.parent = &ithc->pci->dev; +- hid->driver_data = ithc; +- +- ithc->hid = hid; +- return 0; +-} +- + // Interrupts/polling + +-static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t) +-{ +- struct ithc *ithc = container_of(t, struct ithc, activity_start_timer); +- ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC); +- return HRTIMER_NORESTART; +-} +- +-static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t) +-{ +- struct ithc *ithc = container_of(t, struct ithc, activity_end_timer); +- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); +- return HRTIMER_NORESTART; +-} +- +-void ithc_set_active(struct ithc *ithc, unsigned int duration_us) +-{ +- if (ithc_dma_latency_us < 0) +- return; +- // When CPU usage is very low, the CPU can enter various low power states (C2-C10). +- // This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be +- // set when this happens. The amount of truncated messages can become very high, resulting +- // in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency +- // QoS request to prevent the CPU from entering low power states during touch interactions. +- cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us); +- hrtimer_start_range_ns(&ithc->activity_end_timer, +- ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL); +-} +- +-static int ithc_set_device_enabled(struct ithc *ithc, bool enable) +-{ +- u32 x = ithc->config.touch_cfg = +- (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 | +- (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0); +- return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, +- offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); +-} +- + static void ithc_disable_interrupts(struct ithc *ithc) + { + writel(0, &ithc->regs->error_control); + bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); +- bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); +- bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); + bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); + } + + static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) + { +- writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA, ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, + &ithc->regs->dma_rx[channel].status); + } + +@@ -325,39 +128,22 @@ static void ithc_process(struct ithc *ithc) + { + ithc_log_regs(ithc); + ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back here, since ++ // the DMA transfer should be complete. ++ ithc_set_ltr_idle(ithc); ++ + bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; + bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; + +- // Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer +- ktime_t t = ktime_get(); +- ktime_t dt = ktime_sub(t, ithc->last_rx_time); +- if (rx0 || rx1) { +- ithc->last_rx_time = t; +- if (dt > ms_to_ktime(100)) { +- ithc->cur_rx_seq_count = 0; +- ithc->cur_rx_seq_errors = 0; +- } +- ithc->cur_rx_seq_count++; +- if (!ithc_use_polling && ithc_dma_latency_us >= 0) { +- // Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below) +- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); +- hrtimer_try_to_cancel(&ithc->activity_end_timer); +- } +- } +- + // Read and clear error bits + u32 err = readl(&ithc->regs->error_flags); + if (err) { + writel(err, &ithc->regs->error_flags); + if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) + pci_err(ithc->pci, "error flags: 0x%08x\n", err); +- if (err & ERROR_FLAG_DMA_RX_TIMEOUT) { +- // Only log an error if we see a significant number of these errors. +- ithc->cur_rx_seq_errors++; +- if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10) +- pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n", +- ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt)); +- } ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); + } + + // Process DMA rx +@@ -372,12 +158,6 @@ static void ithc_process(struct ithc *ithc) + ithc_dma_rx(ithc, 1); + } + +- // Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT +- if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) { +- ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us)); +- hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS); +- } +- + ithc_log_regs(ithc); + } + +@@ -403,12 +183,8 @@ static int ithc_poll_thread(void *arg) + ithc_process(ithc); + // Decrease polling interval to 20ms if we received data, otherwise slowly + // increase it up to 200ms. +- if (n != ithc->dma_rx[1].num_received) { +- ithc_set_active(ithc, 100 * USEC_PER_MSEC); +- sleep = 20; +- } else { +- sleep = min(200u, sleep + (sleep >> 4) + 1); +- } ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); + msleep_interruptible(sleep); + } + return 0; +@@ -431,73 +207,44 @@ static void ithc_disable(struct ithc *ithc) + + static int ithc_init_device(struct ithc *ithc) + { ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device + ithc_log_regs(ithc); + bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; + ithc_disable(ithc); + CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); +- +- // Since we don't yet know which SPI config the device wants, use default speed and mode +- // initially for reading config data. +- ithc_set_spi_config(ithc, 10, 0); +- +- // Setting the following bit seems to make reading the config more reliable. +- bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000); ++ ithc_log_regs(ithc); + + // If the device was previously enabled, wait a bit to make sure it's fully shut down. + if (was_enabled) + if (msleep_interruptible(100)) + return -EINTR; + +- // Take the touch device out of reset. +- bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); +- CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); +- for (int retries = 0; ; retries++) { +- ithc_log_regs(ithc); +- bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); +- if (!waitl(ithc, &ithc->regs->state, 0xf, 2)) +- break; +- if (retries > 5) { +- pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state)); +- return -ETIMEDOUT; +- } +- pci_warn(ithc->pci, "invalid state, retrying reset\n"); +- bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); +- if (msleep_interruptible(1000)) +- return -EINTR; +- } +- ithc_log_regs(ithc); ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 100us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 100 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); + +- // Waiting for the following status bit makes reading config much more reliable, +- // however the official driver does not seem to do this... +- CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4); +- +- // Read configuration data. +- for (int retries = 0; ; retries++) { +- ithc_log_regs(ithc); +- memset(&ithc->config, 0, sizeof(ithc->config)); +- CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config); +- u32 *p = (void *)&ithc->config; +- pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", +- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); +- if (ithc_is_config_valid(ithc)) +- break; +- if (retries > 10) { +- pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", +- ithc->config.device_id); +- return -EIO; +- } +- pci_warn(ithc->pci, "failed to read config, retrying\n"); +- if (msleep_interruptible(100)) +- return -EINTR; +- } +- ithc_log_regs(ithc); +- +- // Apply SPI config and enable touch device. +- CHECK_RET(ithc_set_spi_config, ithc, +- DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config), +- DEVCFG_SPI_MODE(ithc->config.spi_config)); +- CHECK_RET(ithc_set_device_enabled, ithc, true); +- ithc_log_regs(ithc); + return 0; + } + +@@ -527,11 +274,11 @@ static void ithc_stop(void *res) + CHECK(kthread_stop, ithc->poll_thread); + if (ithc->irq >= 0) + disable_irq(ithc->irq); +- CHECK(ithc_set_device_enabled, ithc, false); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); + ithc_disable(ithc); +- hrtimer_cancel(&ithc->activity_start_timer); +- hrtimer_cancel(&ithc->activity_end_timer); +- cpu_latency_qos_remove_request(&ithc->activity_qos); + + // Clear DMA config. + for (unsigned int i = 0; i < 2; i++) { +@@ -570,9 +317,6 @@ static int ithc_start(struct pci_dev *pci) + ithc->irq = -1; + ithc->pci = pci; + snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); +- init_waitqueue_head(&ithc->wait_hid_parse); +- init_waitqueue_head(&ithc->wait_hid_get_feature); +- mutex_init(&ithc->hid_get_feature_mutex); + pci_set_drvdata(pci, ithc); + CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); + if (ithc_log_regs_enabled) +@@ -596,6 +340,9 @@ static int ithc_start(struct pci_dev *pci) + + // Initialize THC and touch device. + CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); + CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups); + if (ithc_use_rx0) + CHECK_RET(ithc_dma_rx_init, ithc, 0); +@@ -603,18 +350,10 @@ static int ithc_start(struct pci_dev *pci) + CHECK_RET(ithc_dma_rx_init, ithc, 1); + CHECK_RET(ithc_dma_tx_init, ithc); + +- cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); +- hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); +- ithc->activity_start_timer.function = ithc_activity_start_timer_callback; +- hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +- ithc->activity_end_timer.function = ithc_activity_end_timer_callback; +- + // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are + // disabled BEFORE the buffers are freed. + CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); + +- CHECK_RET(ithc_hid_init, ithc); +- + // Start polling/IRQ. + if (ithc_use_polling) { + pci_info(pci, "using polling instead of irq\n"); +@@ -637,9 +376,11 @@ static int ithc_start(struct pci_dev *pci) + + // hid_add_device() can only be called after irq/polling is started and DMA is enabled, + // because it calls ithc_hid_parse() which reads the report descriptor via DMA. +- CHECK_RET(hid_add_device, ithc->hid); ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); + +- CHECK(ithc_debug_init, ithc); ++ ithc_set_ltr_idle(ithc); + + pci_dbg(pci, "started\n"); + return 0; +@@ -710,17 +451,20 @@ static struct pci_driver ithc_driver = { + .thaw = ithc_thaw, + .restore = ithc_restore, + }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, + //.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway + }; + + static int __init ithc_init(void) + { ++ ithc_debug_init_module(); + return pci_register_driver(&ithc_driver); + } + + static void __exit ithc_exit(void) + { + pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); + } + + module_init(ithc_init); +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..760e55ead078 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,578 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ if (cfg->has_read_opcode) { ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_single); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_dual); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_quad); ++ } ++ if (cfg->has_write_opcode) { ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_single); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_dual); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_quad); ++ } ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +index e058721886e3..c0f13506af20 100644 +--- a/drivers/hid/ithc/ithc-regs.c ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -22,46 +22,104 @@ void bitsb(__iomem u8 *reg, u8 mask, u8 val) + + int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) + { ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", + reg_num(reg), mask, val); + u32 x; + if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); + pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", + reg_num(reg), mask, val); + return -ETIMEDOUT; + } ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "done waiting\n"); + return 0; + } + + int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) + { ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", + reg_num(reg), mask, val); + u8 x; + if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); + pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", + reg_num(reg), mask, val); + return -ETIMEDOUT; + } ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "done waiting\n"); + return 0; + } + +-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode) ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) + { +- pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode); +- if (mode == 3) +- mode = 2; ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); + bitsl(&ithc->regs->spi_config, +- SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff), +- SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed)); ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); + return 0; + } + + int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) + { +- pci_dbg(ithc->pci, "SPI command %u, size %u, offset %u\n", command, size, offset); ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); + if (size > sizeof(ithc->regs->spi_cmd.data)) + return -EINVAL; + +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +index d4007d9e2bac..a9d236454644 100644 +--- a/drivers/hid/ithc/ithc-regs.h ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -1,14 +1,34 @@ + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ + #define CONTROL_QUIESCE BIT(1) + #define CONTROL_IS_QUIESCED BIT(2) + #define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) + #define CONTROL_READY BIT(29) + +-#define SPI_CONFIG_MODE(x) (((x) & 3) << 2) +-#define SPI_CONFIG_SPEED(x) (((x) & 7) << 4) +-#define SPI_CONFIG_UNKNOWN_18(x) (((x) & 3) << 18) +-#define SPI_CONFIG_SPEED2(x) (((x) & 0xf) << 20) // high bit = high speed mode? ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 + + #define ERROR_CONTROL_UNKNOWN_0 BIT(0) + #define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs +@@ -53,33 +73,71 @@ + #define DMA_TX_STATUS_UNKNOWN_2 BIT(2) + #define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? + ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ + #define DMA_RX_CONTROL_ENABLE BIT(0) + #define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? + #define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? +-#define DMA_RX_CONTROL_IRQ_UNKNOWN_4 BIT(4) // rx0 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only + #define DMA_RX_CONTROL_IRQ_DATA BIT(5) + ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? + #define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? + #define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices + + #define DMA_RX_WRAP_FLAG BIT(7) + + #define DMA_RX_STATUS_ERROR BIT(3) +-#define DMA_RX_STATUS_UNKNOWN_4 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) + #define DMA_RX_STATUS_HAVE_DATA BIT(5) + #define DMA_RX_STATUS_ENABLED BIT(8) + ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ + // COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. + #define COUNTER_RESET BIT(31) + + struct ithc_registers { +- /* 0000 */ u32 _unknown_0000[1024]; ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; + /* 1000 */ u32 _unknown_1000; + /* 1004 */ u32 _unknown_1004; + /* 1008 */ u32 control_bits; + /* 100c */ u32 _unknown_100c; + /* 1010 */ u32 spi_config; +- /* 1014 */ u32 _unknown_1014[3]; ++ /* 1014 */ u8 read_opcode; // maybe for header? ++ /* 1015 */ u8 read_opcode_quad; ++ /* 1016 */ u8 read_opcode_dual; ++ /* 1017 */ u8 read_opcode_single; ++ /* 1018 */ u8 write_opcode; // not used? ++ /* 1019 */ u8 write_opcode_quad; ++ /* 101a */ u8 write_opcode_dual; ++ /* 101b */ u8 write_opcode_single; ++ /* 101c */ u32 _unknown_101c; + /* 1020 */ u32 error_control; + /* 1024 */ u32 error_status; // write to clear + /* 1028 */ u32 error_flags; // write to clear +@@ -100,12 +158,19 @@ struct ithc_registers { + /* 109a */ u8 _unknown_109a; + /* 109b */ u8 num_prds; + /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; + } dma_tx; +- /* 10a0 */ u32 _unknown_10a0[7]; +- /* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; + /* 10c0 */ u32 _unknown_10c0[8]; + /* 10e0 */ u32 _unknown_10e0_counters[3]; +- /* 10ec */ u32 _unknown_10ec[5]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; + struct { + /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() + /* 1108/1208 */ u8 num_bufs; +@@ -120,70 +185,30 @@ struct ithc_registers { + /* 1118/1218 */ u64 _unknown_1118_guc_addr; + /* 1120/1220 */ u32 _unknown_1120_guc; + /* 1124/1224 */ u32 _unknown_1124_guc; +- /* 1128/1228 */ u32 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related ++ /* 1128/1228 */ u32 init_unknown; + /* 112c/122c */ u32 _unknown_112c; + /* 1130/1230 */ u64 _unknown_1130_guc_addr; + /* 1138/1238 */ u32 _unknown_1138_guc; + /* 113c/123c */ u32 _unknown_113c; + /* 1140/1240 */ u32 _unknown_1140_guc; +- /* 1144/1244 */ u32 _unknown_1144[23]; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; + /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; + /* 11b8/12b8 */ u32 _unknown_11b8[18]; + } dma_rx[2]; + }; + static_assert(sizeof(struct ithc_registers) == 0x1300); + +-#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) +-#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) +- +-#define DEVCFG_TOUCH_MASK 0x3f +-#define DEVCFG_TOUCH_ENABLE BIT(0) +-#define DEVCFG_TOUCH_UNKNOWN_1 BIT(1) +-#define DEVCFG_TOUCH_UNKNOWN_2 BIT(2) +-#define DEVCFG_TOUCH_UNKNOWN_3 BIT(3) +-#define DEVCFG_TOUCH_UNKNOWN_4 BIT(4) +-#define DEVCFG_TOUCH_UNKNOWN_5 BIT(5) +-#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) +- +-#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" +- +-#define DEVCFG_SPI_MAX_FREQ(x) (((x) >> 1) & 0xf) // high bit = use high speed mode? +-#define DEVCFG_SPI_MODE(x) (((x) >> 6) & 3) +-#define DEVCFG_SPI_UNKNOWN_8(x) (((x) >> 8) & 0x3f) +-#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat +-#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) +-#define DEVCFG_SPI_UNKNOWN_25 BIT(25) +-#define DEVCFG_SPI_UNKNOWN_26 BIT(26) +-#define DEVCFG_SPI_UNKNOWN_27 BIT(27) +-#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this +-#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? +- +-struct ithc_device_config { // (Example values are from an SP7+.) +- u32 _unknown_00; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) +- u32 _unknown_04; // 04 = 0x00000000 +- u32 dma_buf_sizes; // 08 = 0x000a00ff +- u32 touch_cfg; // 0c = 0x0000001c +- u32 _unknown_10; // 10 = 0x0000001c +- u32 device_id; // 14 = 0x43495424 = "$TIC" +- u32 spi_config; // 18 = 0xfda00a2e +- u16 vendor_id; // 1c = 0x045e = Microsoft Corp. +- u16 product_id; // 1e = 0x0c1a +- u32 revision; // 20 = 0x00000001 +- u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) +- u32 _unknown_28; // 28 = 0x00000000 +- u32 fw_mode; // 2c = 0x00000000 (for fw update?) +- u32 _unknown_30; // 30 = 0x00000000 +- u32 _unknown_34; // 34 = 0x0404035e (u8,u8,u8,u8 = version?) +- u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) +- u32 _unknown_3c; // 3c = 0x00000002 +-}; +- + void bitsl(__iomem u32 *reg, u32 mask, u32 val); + void bitsb(__iomem u8 *reg, u8 mask, u8 val); + #define bitsl_set(reg, x) bitsl(reg, x, x) + #define bitsb_set(reg, x) bitsb(reg, x, x) + int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); + int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); +-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); + int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); + +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +index 028e55a4ec53..e90c38044432 100644 +--- a/drivers/hid/ithc/ithc.h ++++ b/drivers/hid/ithc/ithc.h +@@ -1,20 +1,19 @@ + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + +-#include +-#include +-#include ++#include ++#include ++#include + #include ++#include + #include +-#include ++#include + #include + #include +-#include + #include + #include +-#include ++#include ++#include + #include +-#include +-#include + + #define DEVNAME "ithc" + #define DEVFULLNAME "Intel Touch Host Controller" +@@ -27,10 +26,37 @@ + + #define NUM_RX_BUF 16 + ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a ++ + struct ithc; + + #include "ithc-regs.h" ++#include "ithc-hid.h" + #include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" + + struct ithc { + char phys[32]; +@@ -38,30 +64,21 @@ struct ithc { + int irq; + struct task_struct *poll_thread; + +- struct pm_qos_request activity_qos; +- struct hrtimer activity_start_timer; +- struct hrtimer activity_end_timer; +- ktime_t last_rx_time; +- unsigned int cur_rx_seq_count; +- unsigned int cur_rx_seq_errors; +- +- struct hid_device *hid; +- bool hid_parse_done; +- wait_queue_head_t wait_hid_parse; +- wait_queue_head_t wait_hid_get_feature; +- struct mutex hid_get_feature_mutex; +- void *hid_get_feature_buf; +- size_t hid_get_feature_size; +- + struct ithc_registers __iomem *regs; + struct ithc_registers *prev_regs; // for debugging +- struct ithc_device_config config; + struct ithc_dma_rx dma_rx[2]; + struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; + }; + + int ithc_reset(struct ithc *ithc); +-void ithc_set_active(struct ithc *ithc, unsigned int duration_us); +-int ithc_debug_init(struct ithc *ithc); +-void ithc_log_regs(struct ithc *ithc); + +-- +2.44.0 + diff --git a/patches/6.8/0006-surface-sam.patch b/patches/6.8/0006-surface-sam.patch index 60808905ef..fd1a2f895d 100644 --- a/patches/6.8/0006-surface-sam.patch +++ b/patches/6.8/0006-surface-sam.patch @@ -1162,3 +1162,57 @@ index a5a3941b3f43..e54d0a8f7daa 100644 -- 2.44.0 +From 63781a056a0f06d5cc38d7755e0753c7ec08c51c Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 19 Apr 2024 20:41:47 +0200 +Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is + destroyed in probe + +There is a small window in ssam_serial_hub_probe() where the controller +is initialized but has not been started yet. Specifically, between +ssam_controller_init() and ssam_controller_start(). Any failure in this +window, for example caused by a failure of serdev_device_open(), +currently results in an incorrect warning being emitted. + +In particular, any failure in this window results in the controller +being destroyed via ssam_controller_destroy(). This function checks the +state of the controller and, in an attempt to validate that the +controller has been cleanly shut down before we try and deallocate any +resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. + +However, since we have only just initialized the controller and have not +yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this +is the only point at which the controller has this state, as it will +change after we start the controller with ssam_controller_start() and +never revert back. Further, at this point no communication has taken +place and the sender and receiver threads have not been started yet (and +we may not even have an open serdev device either). + +Therefore, it is perfectly safe to call ssam_controller_destroy() with a +state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the +warning currently being emitted is incorrect. Fix it by extending the +check. + +Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") +Signed-off-by: Maximilian Luz +--- + drivers/platform/surface/aggregator/controller.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c +index 7fc602e01487..7e89f547999b 100644 +--- a/drivers/platform/surface/aggregator/controller.c ++++ b/drivers/platform/surface/aggregator/controller.c +@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) + if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) + return; + +- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); ++ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && ++ ctrl->state != SSAM_CONTROLLER_INITIALIZED); + + /* + * Note: New events could still have been received after the previous +-- +2.44.0 + From 5a359152167b849e40d7a1a281f1145a449bf64b Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Apr 2024 09:43:17 +0200 Subject: [PATCH 009/236] pkg: debian: Update to v6.8.8 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 5a3cb79058..065db15a13 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.8.6" +KERNEL_VERSION="6.8.8" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From d0480c24a241a30936c2535e69a77b73a672f8b8 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Apr 2024 09:43:55 +0200 Subject: [PATCH 010/236] pkg: fedora: Update to v6.8.8 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 97d9493d45..b16cc967fc 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.8.6-0" +PACKAGE_TAG = "kernel-6.8.8-0" ## ## The release number of the modified kernel package. From e598fa2ca8b691eaf5183f020e188152e7a791ff Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Apr 2024 09:47:24 +0200 Subject: [PATCH 011/236] pkg: arch: Update to v6.8.8 --- pkg/arch/kernel/PKGBUILD | 14 +++++++------- pkg/arch/kernel/config | 14 ++++++-------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 1aa81444cf..740c2e9467 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.8.6.arch1 +pkgver=6.8.8.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -56,16 +56,16 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('2a56b8533af53cf5d3be8882a4a2da34a8d5a2d26569b098102aa072960c32e0' - '9a21f27cdfdb1d7b27af526b2c85632eca890e5264cd44dcb0882e9953794a2a' +sha256sums=('d539ec5682105eb1292bba204f2302e80862947c82b899c9ca38d49021ec30ff' + '0e78254fa2d2718e8912a41047266b9a63aa53fb74198da4389b97fa8bf8c40b' '985cd5e0b11538f31887e451c398d226c06ca4b34c5466e93a21ebd65b7b3919' - '3cabe391cc39dbee88a79f76e9e7a68f7fbcd5518941aa2ab73a77692c87dead' + 'd9a981e75adba8f9762555493293e1d162fbe4c6468e734712941852c33a62aa' 'ee9857e96ee5d871aa557f6d6d142474c26187faa2c21b351bafde065b288fe0' '12f914866916181f232b4f159a270bce1fc8bd8e93c4f86ae7b18f8d6a777573' '1984f355569702ff87cfab75682ceb89bfe40ad22c5c4dd8653abe623e000dfb' - 'be01d5c3e851830be8ef55c794e8480e5cf19ff6b66266db32d352c2c60eebe4' - '0b27a1ea32c6cdbb3ab89866724b0b193998d7ee0525d736242411c2ec3d4bd5' - 'ca4c0bc2b26e3e07c29537cbecc8bade50212d5a0277ae1a834b7c33c36f7c8a' + '7a38f5da1831757ab9e634a14a0e8a05d05d90e1755e97695d7a58c7e33582f9' + '5119cc60f526f8d0f86f59235fbd18e144932b20437d568350bc92d00b70a647' + 'e53393681a6829cd2ab5873a548780c9d340a635511ad314a65e49555d308bd7' '9dd041d482eb7f0479487c5fe127f4fd6bec1209d9cd7d77a73f87b205035238' 'bd32fc7cc18345f027a4fe2af2b249d27470f7b120b1e521dd26008cc34e1e8d' '02d720e3fffae018fc8719a98135e63c84e8b7f39769bcdee45ddf973a567732' diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index 9cc6c3620b..a040589d6f 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,8 +1,8 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.8.6-arch1 Kernel Configuration +# Linux/x86 6.8.8-arch1 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="gcc (GCC) 13.2.1 20230801" +CONFIG_CC_VERSION_TEXT="gcc (GCC) 13.2.1 20240417" CONFIG_CC_IS_GCC=y CONFIG_GCC_VERSION=130201 CONFIG_CLANG_VERSION=0 @@ -566,9 +566,7 @@ CONFIG_CPU_SRSO=y CONFIG_SLS=y # CONFIG_GDS_FORCE_MITIGATION is not set CONFIG_MITIGATION_RFDS=y -CONFIG_SPECTRE_BHI_ON=y -# CONFIG_SPECTRE_BHI_OFF is not set -# CONFIG_SPECTRE_BHI_AUTO is not set +CONFIG_MITIGATION_SPECTRE_BHI=y CONFIG_ARCH_HAS_ADD_PAGES=y # @@ -4617,7 +4615,7 @@ CONFIG_MOXA_INTELLIO=m CONFIG_MOXA_SMARTIO=m CONFIG_N_HDLC=m CONFIG_IPWIRELESS=m -CONFIG_N_GSM=m +# CONFIG_N_GSM is not set CONFIG_NOZOMI=m CONFIG_NULL_TTY=m CONFIG_HVC_DRIVER=y @@ -10456,9 +10454,9 @@ CONFIG_QFMT_V1=m CONFIG_QFMT_V2=m CONFIG_QUOTACTL=y CONFIG_AUTOFS_FS=y -CONFIG_FUSE_FS=m +CONFIG_FUSE_FS=y CONFIG_CUSE=m -CONFIG_VIRTIO_FS=m +CONFIG_VIRTIO_FS=y CONFIG_FUSE_DAX=y CONFIG_OVERLAY_FS=m CONFIG_OVERLAY_FS_REDIRECT_DIR=y From aa2264ac4583bdaf8657fc12f1d7faa25e176c02 Mon Sep 17 00:00:00 2001 From: Matt Leon Date: Sat, 1 Jun 2024 10:26:10 -0400 Subject: [PATCH 012/236] Add patches for 6.9 Patches derived from applying 6.8 patches atop github.com/grekh/linux v6.9.3 (1b4861e32e46) and fixing the conflicts. Notable conflicts * 0004-ipts.patch * Some changes to drivers/iommu/intel/iommu.c caused merge conflicts because adjacent workarounds were removed in ba00196ca41c. It does not appear to matter. * 0012-cameras.patch * "media: ipu3-cio2: Further clean up async subdev link creation" seems to have been upstreamed as commit b97dc22b195f --- configs/surface-6.9.config | 75 + patches/6.9/0001-surface3-oemb.patch | 101 + patches/6.9/0002-mwifiex.patch | 402 ++ patches/6.9/0003-ath10k.patch | 121 + patches/6.9/0004-ipts.patch | 3294 ++++++++++++++ patches/6.9/0005-ithc.patch | 4341 +++++++++++++++++++ patches/6.9/0006-surface-sam.patch | 957 ++++ patches/6.9/0007-surface-sam-over-hid.patch | 337 ++ patches/6.9/0008-surface-button.patch | 151 + patches/6.9/0009-surface-typecover.patch | 575 +++ patches/6.9/0010-surface-shutdown.patch | 97 + patches/6.9/0011-surface-gpe.patch | 51 + patches/6.9/0012-cameras.patch | 790 ++++ patches/6.9/0013-amd-gpio.patch | 110 + patches/6.9/0014-rtc.patch | 110 + 15 files changed, 11512 insertions(+) create mode 100644 configs/surface-6.9.config create mode 100644 patches/6.9/0001-surface3-oemb.patch create mode 100644 patches/6.9/0002-mwifiex.patch create mode 100644 patches/6.9/0003-ath10k.patch create mode 100644 patches/6.9/0004-ipts.patch create mode 100644 patches/6.9/0005-ithc.patch create mode 100644 patches/6.9/0006-surface-sam.patch create mode 100644 patches/6.9/0007-surface-sam-over-hid.patch create mode 100644 patches/6.9/0008-surface-button.patch create mode 100644 patches/6.9/0009-surface-typecover.patch create mode 100644 patches/6.9/0010-surface-shutdown.patch create mode 100644 patches/6.9/0011-surface-gpe.patch create mode 100644 patches/6.9/0012-cameras.patch create mode 100644 patches/6.9/0013-amd-gpio.patch create mode 100644 patches/6.9/0014-rtc.patch diff --git a/configs/surface-6.9.config b/configs/surface-6.9.config new file mode 100644 index 0000000000..fedb251cf3 --- /dev/null +++ b/configs/surface-6.9.config @@ -0,0 +1,75 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m diff --git a/patches/6.9/0001-surface3-oemb.patch b/patches/6.9/0001-surface3-oemb.patch new file mode 100644 index 0000000000..3a83c37c15 --- /dev/null +++ b/patches/6.9/0001-surface3-oemb.patch @@ -0,0 +1,101 @@ +From 77d6e5b59e54e265d824fa4fd8e342cb79ba52e4 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-oemb +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index c15ed7a12784..1ec8edb5aafa 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index d0d24a53df74..43e06166a5d9 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3777,6 +3777,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index 5e2ec60e2954..207868c699f2 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.44.1 + diff --git a/patches/6.9/0002-mwifiex.patch b/patches/6.9/0002-mwifiex.patch new file mode 100644 index 0000000000..4912f75e9d --- /dev/null +++ b/patches/6.9/0002-mwifiex.patch @@ -0,0 +1,402 @@ +From 38ff71a84e7a1ad3de25056f8e5629eb749a85e8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH 1/3] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.44.1 + + +From 47109fad48e842ffedf33bcb07f5080e1350337d Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH 2/3] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.44.1 + + +From 57cd8aeebe2fd4913281c93611277fca158a9c77 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH 3/3] Bluetooth: btusb: Lower passive lescan interval on + Marvell 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index fb716849b60f..1e7b3798108f 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -468,6 +469,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -4417,6 +4419,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.44.1 + diff --git a/patches/6.9/0003-ath10k.patch b/patches/6.9/0003-ath10k.patch new file mode 100644 index 0000000000..a856c01d2d --- /dev/null +++ b/patches/6.9/0003-ath10k.patch @@ -0,0 +1,121 @@ +From be4b537a27b26a55c4557398ebeead056c446c1b Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 58 ++++++++++++++++++++++++++ + 1 file changed, 58 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index fa5e2e651831..8921b0ebf36b 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -39,6 +39,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -51,6 +54,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -60,6 +66,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,19 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + snprintf(filename, sizeof(filename), "%s/%s", dir, file); + ret = firmware_request_nowarn(&fw, filename, ar->dev); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", +-- +2.44.1 + diff --git a/patches/6.9/0004-ipts.patch b/patches/6.9/0004-ipts.patch new file mode 100644 index 0000000000..d01dbb63ed --- /dev/null +++ b/patches/6.9/0004-ipts.patch @@ -0,0 +1,3294 @@ +From 64bf8dc5156002a92eab306a503ae7e89a7ca3be Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH 1/4] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 7f59dd38c32f..a56ad5b3f779 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.44.1 + + +From 8ac49646a71a247ca8ce3348572809866d7d4cd0 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH 2/4] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index e4a03588a8a0..61bc54299a59 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -39,6 +39,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -221,12 +226,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -2401,6 +2408,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2701,6 +2711,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + ret = si_domain_init(hw_pass_through); +@@ -4871,6 +4884,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4906,6 +4931,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.44.1 + + +From d7581a727eabc72550a834ae375f20db53da63ee Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH 3/4] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 103 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 144 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 250 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2850 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 4c682c650704..a263e49b2ae2 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1351,4 +1351,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + + source "drivers/hid/surface-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 082a728eac60..f4bad1b8d813 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -170,3 +170,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..ecbb3a8bdaf6 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,103 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..198dc65d7887 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,144 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..ef66c3c9db80 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,250 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.44.1 + + +From 802ca4119a92827eddcb63610261fb8dbbae4eba Mon Sep 17 00:00:00 2001 +From: Jasmin Huber +Date: Mon, 15 Apr 2024 10:22:55 +0200 +Subject: [PATCH 4/4] Inlude headers to avoid compiler warnings 6.8 kernels + compile with -Wmissing-prototypes. + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/ipts/eds1.c | 1 + + drivers/hid/ipts/eds2.c | 1 + + drivers/hid/ipts/receiver.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +index ecbb3a8bdaf6..7b9f54388a9f 100644 +--- a/drivers/hid/ipts/eds1.c ++++ b/drivers/hid/ipts/eds1.c +@@ -14,6 +14,7 @@ + #include "context.h" + #include "control.h" + #include "desc.h" ++#include "eds1.h" + #include "spec-device.h" + + int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +index 198dc65d7887..639940794615 100644 +--- a/drivers/hid/ipts/eds2.c ++++ b/drivers/hid/ipts/eds2.c +@@ -15,6 +15,7 @@ + #include "context.h" + #include "control.h" + #include "desc.h" ++#include "eds2.h" + #include "spec-data.h" + + int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +index ef66c3c9db80..977724c728c3 100644 +--- a/drivers/hid/ipts/receiver.c ++++ b/drivers/hid/ipts/receiver.c +@@ -16,6 +16,7 @@ + #include "context.h" + #include "control.h" + #include "hid.h" ++#include "receiver.h" + #include "resources.h" + #include "spec-device.h" + #include "thread.h" +-- +2.44.1 + diff --git a/patches/6.9/0005-ithc.patch b/patches/6.9/0005-ithc.patch new file mode 100644 index 0000000000..0c749a450f --- /dev/null +++ b/patches/6.9/0005-ithc.patch @@ -0,0 +1,4341 @@ +From c6eae6f4321c2daafedaaf1f81201eed78291c8b Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH 1/3] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 566297bc87dd..a8cd8f12d593 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -386,6 +386,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.44.1 + + +From 9269060ff3088a0d1c33cf7ca134f1db48c99fd6 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH 2/3] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@0b8b45d + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 130 ++++++ + drivers/hid/ithc/ithc-dma.c | 373 +++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 69 ++++ + drivers/hid/ithc/ithc-main.c | 728 ++++++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-regs.c | 96 +++++ + drivers/hid/ithc/ithc-regs.h | 189 +++++++++ + drivers/hid/ithc/ithc.h | 67 ++++ + 11 files changed, 1673 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index a263e49b2ae2..03f0f5af289a 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1353,4 +1353,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index f4bad1b8d813..d32c194400ae 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..aea83f2ac07b +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..1f1f1e33f2e5 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,130 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 2 || a[1] > (n - 2) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]); ++ if (ithc_dma_tx(ithc, a[0], a[1], a + 2)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ if (*dbgm) ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init(struct ithc *ithc) ++{ ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..ffb8689b8a78 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,373 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes); ++ unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, buf_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes); ++ unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ tx->max_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data, ++ u8 channel, u8 buf) ++{ ++ if (buf >= NUM_RX_BUF) { ++ pci_err(ithc->pci, "invalid dma ringbuffer index\n"); ++ return -EINVAL; ++ } ++ u32 len = data->data_size; ++ struct ithc_dma_rx_header *hdr = data->addr; ++ u8 *hiddata = (void *)(hdr + 1); ++ if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) { ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ CHECK(ithc_reset, ithc); ++ } else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) { ++ if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { ++ // When the CPU enters a low power state during DMA, we can get truncated ++ // messages. For Surface devices, this will typically be a single touch ++ // report that is only 1 byte, or a multitouch report that is 257 bytes. ++ // See also ithc_set_active(). ++ } else { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n", ++ channel, buf, len, hdr->code, hdr->data_size); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ hdr, min(len, 0x400u), 0); ++ } ++ } else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) { ++ // Response to a 'get report descriptor' request. ++ // The actual descriptor is preceded by 8 nul bytes. ++ CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8); ++ WRITE_ONCE(ithc->hid_parse_done, true); ++ wake_up(&ithc->wait_hid_parse); ++ } else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { ++ // Standard HID input report containing touch data. ++ CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1); ++ } else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) { ++ // Response to a 'get feature' request. ++ bool done = false; ++ mutex_lock(&ithc->hid_get_feature_mutex); ++ if (ithc->hid_get_feature_buf) { ++ if (hdr->data_size < ithc->hid_get_feature_size) ++ ithc->hid_get_feature_size = hdr->data_size; ++ memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size); ++ ithc->hid_get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid_get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->wait_hid_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT, ++ hiddata, hdr->data_size, 1); ++ } ++ } else { ++ pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n", ++ channel, buf, len, hdr->code); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ hdr, min(len, 0x400u), 0); ++ } ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail); ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) ++{ ++ ithc_set_active(ithc, 100 * USEC_PER_MSEC); ++ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize); ++ struct ithc_dma_tx_header *hdr; ++ // Data must be padded to next 4-byte boundary. ++ u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0; ++ unsigned int fullsize = sizeof(*hdr) + datasize + padding; ++ if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE) ++ return -EINVAL; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ithc->dma_tx.buf.data_size = fullsize; ++ hdr = ithc->dma_tx.buf.addr; ++ hdr->code = cmdcode; ++ hdr->data_size = datasize; ++ u8 *dest = (void *)(hdr + 1); ++ memcpy(dest, data, datasize); ++ dest += datasize; ++ for (u8 p = 0; p < padding; p++) ++ *dest++ = 0; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..93652e4476bf +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,69 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++#define DMA_RX_CODE_INPUT_REPORT 3 ++#define DMA_RX_CODE_FEATURE_REPORT 4 ++#define DMA_RX_CODE_REPORT_DESCRIPTOR 5 ++#define DMA_RX_CODE_RESET 7 ++ ++struct ithc_dma_rx_header { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++}; ++ ++#define DMA_TX_CODE_SET_FEATURE 3 ++#define DMA_TX_CODE_GET_FEATURE 4 ++#define DMA_TX_CODE_OUTPUT_REPORT 5 ++#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++struct ithc_dma_tx_header { ++ u32 code; ++ u32 data_size; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ u32 max_size; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..87ed4aa70fda +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,728 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_MTL_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_MTL_PORT2) }, ++ // XXX So far the THC seems to be the only Intel PCI device with PCI_CLASS_INPUT_PEN, ++ // so instead of the device list we could just do: ++ // { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .class = PCI_CLASS_INPUT_PEN, .class_mask = ~0, }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering. ++static int ithc_dma_latency_us = 200; ++module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0); ++MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS"); ++ ++// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering. ++static unsigned int ithc_dma_early_us = 2000; ++module_param_named(dma_early_us, ithc_dma_early_us, uint, 0); ++MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Sysfs attributes ++ ++static bool ithc_is_config_valid(struct ithc *ithc) ++{ ++ return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC; ++} ++ ++static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ithc *ithc = dev_get_drvdata(dev); ++ if (!ithc || !ithc_is_config_valid(ithc)) ++ return -ENODEV; ++ return sprintf(buf, "0x%04x", ithc->config.vendor_id); ++} ++static DEVICE_ATTR_RO(vendor); ++static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ithc *ithc = dev_get_drvdata(dev); ++ if (!ithc || !ithc_is_config_valid(ithc)) ++ return -ENODEV; ++ return sprintf(buf, "0x%04x", ithc->config.product_id); ++} ++static DEVICE_ATTR_RO(product); ++static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ithc *ithc = dev_get_drvdata(dev); ++ if (!ithc || !ithc_is_config_valid(ithc)) ++ return -ENODEV; ++ return sprintf(buf, "%u", ithc->config.revision); ++} ++static DEVICE_ATTR_RO(revision); ++static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct ithc *ithc = dev_get_drvdata(dev); ++ if (!ithc || !ithc_is_config_valid(ithc)) ++ return -ENODEV; ++ u32 v = ithc->config.fw_version; ++ return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff); ++} ++static DEVICE_ATTR_RO(fw_version); ++ ++static const struct attribute_group *ithc_attribute_groups[] = { ++ &(const struct attribute_group){ ++ .name = DEVNAME, ++ .attrs = (struct attribute *[]){ ++ &dev_attr_vendor.attr, ++ &dev_attr_product.attr, ++ &dev_attr_revision.attr, ++ &dev_attr_fw_version.attr, ++ NULL ++ }, ++ }, ++ NULL ++}; ++ ++// HID setup ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ u64 val = 0; ++ WRITE_ONCE(ithc->hid_parse_done, false); ++ for (int retries = 0; ; retries++) { ++ CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val); ++ if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done), ++ msecs_to_jiffies(200))) ++ return 0; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ u32 code; ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ code = DMA_TX_CODE_OUTPUT_REPORT; ++ } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ code = DMA_TX_CODE_SET_FEATURE; ++ } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ code = DMA_TX_CODE_GET_FEATURE; ++ } else { ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++ } ++ buf[0] = reportnum; ++ ++ if (reqtype == HID_REQ_GET_REPORT) { ++ // Prepare for response. ++ mutex_lock(&ithc->hid_get_feature_mutex); ++ ithc->hid_get_feature_buf = buf; ++ ithc->hid_get_feature_size = len; ++ mutex_unlock(&ithc->hid_get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, code, 1, buf); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature, ++ !ithc->hid_get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid_get_feature_mutex); ++ ithc->hid_get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid_get_feature_size; ++ mutex_unlock(&ithc->hid_get_feature_mutex); ++ return r; ++ } ++ ++ // 'Set feature', or 'output report'. These don't have a response. ++ CHECK_RET(ithc_dma_tx, ithc, code, len, buf); ++ return 0; ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++static int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->config.vendor_id; ++ hid->product = ithc->config.product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid = hid; ++ return 0; ++} ++ ++// Interrupts/polling ++ ++static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, activity_start_timer); ++ ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC); ++ return HRTIMER_NORESTART; ++} ++ ++static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, activity_end_timer); ++ cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); ++ return HRTIMER_NORESTART; ++} ++ ++void ithc_set_active(struct ithc *ithc, unsigned int duration_us) ++{ ++ if (ithc_dma_latency_us < 0) ++ return; ++ // When CPU usage is very low, the CPU can enter various low power states (C2-C10). ++ // This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be ++ // set when this happens. The amount of truncated messages can become very high, resulting ++ // in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency ++ // QoS request to prevent the CPU from entering low power states during touch interactions. ++ cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us); ++ hrtimer_start_range_ns(&ithc->activity_end_timer, ++ ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL); ++} ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->config.touch_cfg = ++ (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer ++ ktime_t t = ktime_get(); ++ ktime_t dt = ktime_sub(t, ithc->last_rx_time); ++ if (rx0 || rx1) { ++ ithc->last_rx_time = t; ++ if (dt > ms_to_ktime(100)) { ++ ithc->cur_rx_seq_count = 0; ++ ithc->cur_rx_seq_errors = 0; ++ } ++ ithc->cur_rx_seq_count++; ++ if (!ithc_use_polling && ithc_dma_latency_us >= 0) { ++ // Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below) ++ cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); ++ hrtimer_try_to_cancel(&ithc->activity_end_timer); ++ } ++ } ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) { ++ // Only log an error if we see a significant number of these errors. ++ ithc->cur_rx_seq_errors++; ++ if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10) ++ pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n", ++ ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt)); ++ } ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ // Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT ++ if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) { ++ ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us)); ++ hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ if (n != ithc->dma_rx[1].num_received) { ++ ithc_set_active(ithc, 100 * USEC_PER_MSEC); ++ sleep = 20; ++ } else { ++ sleep = min(200u, sleep + (sleep >> 4) + 1); ++ } ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ ithc_set_spi_config(ithc, 10, 0); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->state, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid state, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Waiting for the following status bit makes reading config much more reliable, ++ // however the official driver does not seem to do this... ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4); ++ ++ // Read configuration data. ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ memset(&ithc->config, 0, sizeof(ithc->config)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config); ++ u32 *p = (void *)&ithc->config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (ithc_is_config_valid(ithc)) ++ break; ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ ithc->config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config), ++ DEVCFG_SPI_MODE(ithc->config.spi_config)); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ CHECK(ithc_set_device_enabled, ithc, false); ++ ithc_disable(ithc); ++ hrtimer_cancel(&ithc->activity_start_timer); ++ hrtimer_cancel(&ithc->activity_end_timer); ++ cpu_latency_qos_remove_request(&ithc->activity_qos); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ init_waitqueue_head(&ithc->wait_hid_parse); ++ init_waitqueue_head(&ithc->wait_hid_get_feature); ++ mutex_init(&ithc->hid_get_feature_mutex); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); ++ hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ++ ithc->activity_start_timer.function = ithc_activity_start_timer_callback; ++ hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ ithc->activity_end_timer.function = ithc_activity_end_timer_callback; ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ CHECK_RET(ithc_hid_init, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid); ++ ++ CHECK(ithc_debug_init, ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ //.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway ++}; ++ ++static int __init ithc_init(void) ++{ ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..e058721886e3 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,96 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode) ++{ ++ pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode); ++ if (mode == 3) ++ mode = 2; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff), ++ SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset %u\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..d4007d9e2bac +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,189 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_SPEED(x) (((x) & 7) << 4) ++#define SPI_CONFIG_UNKNOWN_18(x) (((x) & 3) << 18) ++#define SPI_CONFIG_SPEED2(x) (((x) & 0xf) << 20) // high bit = high speed mode? ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_4 BIT(4) // rx0 only? ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_UNKNOWN_4 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[1024]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ /* 1014 */ u32 _unknown_1014[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ } dma_tx; ++ /* 10a0 */ u32 _unknown_10a0[7]; ++ /* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 _unknown_10ec[5]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[23]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_UNKNOWN_1 BIT(1) ++#define DEVCFG_TOUCH_UNKNOWN_2 BIT(2) ++#define DEVCFG_TOUCH_UNKNOWN_3 BIT(3) ++#define DEVCFG_TOUCH_UNKNOWN_4 BIT(4) ++#define DEVCFG_TOUCH_UNKNOWN_5 BIT(5) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_MAX_FREQ(x) (((x) >> 1) & 0xf) // high bit = use high speed mode? ++#define DEVCFG_SPI_MODE(x) (((x) >> 6) & 3) ++#define DEVCFG_SPI_UNKNOWN_8(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 _unknown_00; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 _unknown_04; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 _unknown_10; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 _unknown_28; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u32 _unknown_34; // 34 = 0x0404035e (u8,u8,u8,u8 = version?) ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..028e55a4ec53 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,67 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-dma.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ ++ struct pm_qos_request activity_qos; ++ struct hrtimer activity_start_timer; ++ struct hrtimer activity_end_timer; ++ ktime_t last_rx_time; ++ unsigned int cur_rx_seq_count; ++ unsigned int cur_rx_seq_errors; ++ ++ struct hid_device *hid; ++ bool hid_parse_done; ++ wait_queue_head_t wait_hid_parse; ++ wait_queue_head_t wait_hid_get_feature; ++ struct mutex hid_get_feature_mutex; ++ void *hid_get_feature_buf; ++ size_t hid_get_feature_size; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_device_config config; ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++void ithc_set_active(struct ithc *ithc, unsigned int duration_us); ++int ithc_debug_init(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +-- +2.44.1 + + +From b6f9694876ec4a59690a80e4ee6affcc740cca9a Mon Sep 17 00:00:00 2001 +From: quo +Date: Fri, 19 Apr 2024 22:11:09 +0200 +Subject: [PATCH 3/3] hid: ithc: Update from quo/ithc-linux + + - Added QuickSPI support for Surface Laptop Studio 2 + - Use Latency Tolerance Reporting instead of manual CPU latency adjustments + +Based on: https://github.com/quo/ithc-linux/commit/18afc6ffacd70b49fdee2eb1ab0a8acd159edb31 + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/hid/ithc/Kbuild | 2 +- + drivers/hid/ithc/ithc-debug.c | 33 +- + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 125 ++----- + drivers/hid/ithc/ithc-dma.h | 24 +- + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 252 ++++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 384 ++++---------------- + drivers/hid/ithc/ithc-quickspi.c | 578 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 +++ + drivers/hid/ithc/ithc-regs.c | 72 +++- + drivers/hid/ithc/ithc-regs.h | 143 ++++---- + drivers/hid/ithc/ithc.h | 71 ++-- + 15 files changed, 1440 insertions(+), 537 deletions(-) + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +index aea83f2ac07b..4937ba131297 100644 +--- a/drivers/hid/ithc/Kbuild ++++ b/drivers/hid/ithc/Kbuild +@@ -1,6 +1,6 @@ + obj-$(CONFIG_HID_ITHC) := ithc.o + +-ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-debug.o ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o + + ccflags-y := -std=gnu11 -Wno-declaration-after-statement + +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +index 1f1f1e33f2e5..2d8c6afe9966 100644 +--- a/drivers/hid/ithc/ithc-debug.c ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -85,10 +85,11 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si + case 'd': // dma command: cmd len data... + // get report descriptor: d 7 8 0 0 + // enable multitouch: d 3 2 0x0105 +- if (n < 2 || a[1] > (n - 2) * 4) ++ if (n < 1) + return -EINVAL; +- pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]); +- if (ithc_dma_tx(ithc, a[0], a[1], a + 2)) ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) + pci_err(ithc->pci, "dma tx failed\n"); + break; + default: +@@ -98,6 +99,23 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si + return len; + } + ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ + static const struct file_operations ithc_debugfops_cmd = { + .owner = THIS_MODULE, + .write = ithc_debugfs_cmd_write, +@@ -106,17 +124,18 @@ static const struct file_operations ithc_debugfops_cmd = { + static void ithc_debugfs_devres_release(struct device *dev, void *res) + { + struct dentry **dbgm = res; +- if (*dbgm) +- debugfs_remove_recursive(*dbgm); ++ debugfs_remove_recursive(*dbgm); + } + +-int ithc_debug_init(struct ithc *ithc) ++int ithc_debug_init_device(struct ithc *ithc) + { ++ if (!dbg_dir) ++ return -ENOENT; + struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); + if (!dbgm) + return -ENOMEM; + devres_add(&ithc->pci->dev, dbgm); +- struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); + if (IS_ERR(dbg)) + return PTR_ERR(dbg); + *dbgm = dbg; +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +index ffb8689b8a78..bf4eab33062b 100644 +--- a/drivers/hid/ithc/ithc-dma.c ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -173,10 +173,9 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel) + mutex_init(&rx->mutex); + + // Allocate buffers. +- u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes); +- unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; + pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", +- NUM_RX_BUF, buf_size, num_pages); ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); + CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); + for (unsigned int i = 0; i < NUM_RX_BUF; i++) + CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); +@@ -214,10 +213,9 @@ int ithc_dma_tx_init(struct ithc *ithc) + mutex_init(&tx->mutex); + + // Allocate buffers. +- tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes); +- unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; + pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", +- tx->max_size, num_pages); ++ ithc->max_tx_size, num_pages); + CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); + CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); + +@@ -230,71 +228,6 @@ int ithc_dma_tx_init(struct ithc *ithc) + return 0; + } + +-static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data, +- u8 channel, u8 buf) +-{ +- if (buf >= NUM_RX_BUF) { +- pci_err(ithc->pci, "invalid dma ringbuffer index\n"); +- return -EINVAL; +- } +- u32 len = data->data_size; +- struct ithc_dma_rx_header *hdr = data->addr; +- u8 *hiddata = (void *)(hdr + 1); +- if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) { +- // The THC sends a reset request when we need to reinitialize the device. +- // This usually only happens if we send an invalid command or put the device +- // in a bad state. +- CHECK(ithc_reset, ithc); +- } else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) { +- if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { +- // When the CPU enters a low power state during DMA, we can get truncated +- // messages. For Surface devices, this will typically be a single touch +- // report that is only 1 byte, or a multitouch report that is 257 bytes. +- // See also ithc_set_active(). +- } else { +- pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n", +- channel, buf, len, hdr->code, hdr->data_size); +- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, +- hdr, min(len, 0x400u), 0); +- } +- } else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) { +- // Response to a 'get report descriptor' request. +- // The actual descriptor is preceded by 8 nul bytes. +- CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8); +- WRITE_ONCE(ithc->hid_parse_done, true); +- wake_up(&ithc->wait_hid_parse); +- } else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { +- // Standard HID input report containing touch data. +- CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1); +- } else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) { +- // Response to a 'get feature' request. +- bool done = false; +- mutex_lock(&ithc->hid_get_feature_mutex); +- if (ithc->hid_get_feature_buf) { +- if (hdr->data_size < ithc->hid_get_feature_size) +- ithc->hid_get_feature_size = hdr->data_size; +- memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size); +- ithc->hid_get_feature_buf = NULL; +- done = true; +- } +- mutex_unlock(&ithc->hid_get_feature_mutex); +- if (done) { +- wake_up(&ithc->wait_hid_get_feature); +- } else { +- // Received data without a matching request, or the request already +- // timed out. (XXX What's the correct thing to do here?) +- CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT, +- hiddata, hdr->data_size, 1); +- } +- } else { +- pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n", +- channel, buf, len, hdr->code); +- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, +- hdr, min(len, 0x400u), 0); +- } +- return 0; +-} +- + static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) + { + // Process all filled RX buffers from the ringbuffer. +@@ -316,7 +249,16 @@ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) + rx->num_received = ++n; + + // process data +- CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail); ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } + + // give the buffer back to the device + CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); +@@ -331,31 +273,28 @@ int ithc_dma_rx(struct ithc *ithc, u8 channel) + return ret; + } + +-static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) + { +- ithc_set_active(ithc, 100 * USEC_PER_MSEC); +- + // Send a single TX buffer to the THC. +- pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize); +- struct ithc_dma_tx_header *hdr; +- // Data must be padded to next 4-byte boundary. +- u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0; +- unsigned int fullsize = sizeof(*hdr) + datasize + padding; +- if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE) +- return -EINVAL; ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); + CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); + + // Fill the TX buffer with header and data. +- ithc->dma_tx.buf.data_size = fullsize; +- hdr = ithc->dma_tx.buf.addr; +- hdr->code = cmdcode; +- hdr->data_size = datasize; +- u8 *dest = (void *)(hdr + 1); +- memcpy(dest, data, datasize); +- dest += datasize; +- for (u8 p = 0; p < padding; p++) +- *dest++ = 0; ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; + CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } + + // Let the THC process the buffer. + bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); +@@ -363,10 +302,10 @@ static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, vo + writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); + return 0; + } +-int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) + { + mutex_lock(&ithc->dma_tx.mutex); +- int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data); ++ int ret = ithc_dma_tx_unlocked(ithc, data); + mutex_unlock(&ithc->dma_tx.mutex); + return ret; + } +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +index 93652e4476bf..1749a5819b3e 100644 +--- a/drivers/hid/ithc/ithc-dma.h ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -11,27 +11,6 @@ struct ithc_phys_region_desc { + u32 unused; + }; + +-#define DMA_RX_CODE_INPUT_REPORT 3 +-#define DMA_RX_CODE_FEATURE_REPORT 4 +-#define DMA_RX_CODE_REPORT_DESCRIPTOR 5 +-#define DMA_RX_CODE_RESET 7 +- +-struct ithc_dma_rx_header { +- u32 code; +- u32 data_size; +- u32 _unknown[14]; +-}; +- +-#define DMA_TX_CODE_SET_FEATURE 3 +-#define DMA_TX_CODE_GET_FEATURE 4 +-#define DMA_TX_CODE_OUTPUT_REPORT 5 +-#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7 +- +-struct ithc_dma_tx_header { +- u32 code; +- u32 data_size; +-}; +- + struct ithc_dma_prd_buffer { + void *addr; + dma_addr_t dma_addr; +@@ -49,7 +28,6 @@ struct ithc_dma_data_buffer { + + struct ithc_dma_tx { + struct mutex mutex; +- u32 max_size; + struct ithc_dma_prd_buffer prds; + struct ithc_dma_data_buffer buf; + }; +@@ -65,5 +43,5 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel); + void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); + int ithc_dma_tx_init(struct ithc *ithc); + int ithc_dma_rx(struct ithc *ithc, u8 channel); +-int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); + +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..5c1da11e3f1d +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,252 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on some ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +index 87ed4aa70fda..2acf02e41d40 100644 +--- a/drivers/hid/ithc/ithc-main.c ++++ b/drivers/hid/ithc/ithc-main.c +@@ -5,28 +5,6 @@ + MODULE_DESCRIPTION("Intel Touch Host Controller driver"); + MODULE_LICENSE("Dual BSD/GPL"); + +-// Lakefield +-#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 +-#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 +-// Tiger Lake +-#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 +-#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 +-#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 +-#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 +-// Alder Lake +-#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 +-#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 +-// Raptor Lake +-#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 +-#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 +-// Meteor Lake +-#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 +-#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a +- + static const struct pci_device_id ithc_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, +@@ -66,15 +44,13 @@ static bool ithc_use_rx1 = true; + module_param_named(rx1, ithc_use_rx1, bool, 0); + MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); + +-// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering. +-static int ithc_dma_latency_us = 200; +-module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0); +-MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS"); ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); + +-// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering. +-static unsigned int ithc_dma_early_us = 2000; +-module_param_named(dma_early_us, ithc_dma_early_us, uint, 0); +-MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)"); ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); + + static bool ithc_log_regs_enabled = false; + module_param_named(logregs, ithc_log_regs_enabled, bool, 0); +@@ -82,44 +58,30 @@ MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); + + // Sysfs attributes + +-static bool ithc_is_config_valid(struct ithc *ithc) +-{ +- return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC; +-} +- + static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc_is_config_valid(ithc)) ++ if (!ithc || !ithc->have_config) + return -ENODEV; +- return sprintf(buf, "0x%04x", ithc->config.vendor_id); ++ return sprintf(buf, "0x%04x", ithc->vendor_id); + } + static DEVICE_ATTR_RO(vendor); + static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc_is_config_valid(ithc)) ++ if (!ithc || !ithc->have_config) + return -ENODEV; +- return sprintf(buf, "0x%04x", ithc->config.product_id); ++ return sprintf(buf, "0x%04x", ithc->product_id); + } + static DEVICE_ATTR_RO(product); + static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc_is_config_valid(ithc)) ++ if (!ithc || !ithc->have_config) + return -ENODEV; +- return sprintf(buf, "%u", ithc->config.revision); ++ return sprintf(buf, "%u", ithc->product_rev); + } + static DEVICE_ATTR_RO(revision); +-static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc_is_config_valid(ithc)) +- return -ENODEV; +- u32 v = ithc->config.fw_version; +- return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff); +-} +-static DEVICE_ATTR_RO(fw_version); + + static const struct attribute_group *ithc_attribute_groups[] = { + &(const struct attribute_group){ +@@ -128,185 +90,26 @@ static const struct attribute_group *ithc_attribute_groups[] = { + &dev_attr_vendor.attr, + &dev_attr_product.attr, + &dev_attr_revision.attr, +- &dev_attr_fw_version.attr, + NULL + }, + }, + NULL + }; + +-// HID setup +- +-static int ithc_hid_start(struct hid_device *hdev) { return 0; } +-static void ithc_hid_stop(struct hid_device *hdev) { } +-static int ithc_hid_open(struct hid_device *hdev) { return 0; } +-static void ithc_hid_close(struct hid_device *hdev) { } +- +-static int ithc_hid_parse(struct hid_device *hdev) +-{ +- struct ithc *ithc = hdev->driver_data; +- u64 val = 0; +- WRITE_ONCE(ithc->hid_parse_done, false); +- for (int retries = 0; ; retries++) { +- CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val); +- if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done), +- msecs_to_jiffies(200))) +- return 0; +- if (retries > 5) { +- pci_err(ithc->pci, "failed to read report descriptor\n"); +- return -ETIMEDOUT; +- } +- pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); +- } +-} +- +-static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, +- size_t len, unsigned char rtype, int reqtype) +-{ +- struct ithc *ithc = hdev->driver_data; +- if (!buf || !len) +- return -EINVAL; +- u32 code; +- if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { +- code = DMA_TX_CODE_OUTPUT_REPORT; +- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { +- code = DMA_TX_CODE_SET_FEATURE; +- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { +- code = DMA_TX_CODE_GET_FEATURE; +- } else { +- pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", +- rtype, reqtype, reportnum); +- return -EINVAL; +- } +- buf[0] = reportnum; +- +- if (reqtype == HID_REQ_GET_REPORT) { +- // Prepare for response. +- mutex_lock(&ithc->hid_get_feature_mutex); +- ithc->hid_get_feature_buf = buf; +- ithc->hid_get_feature_size = len; +- mutex_unlock(&ithc->hid_get_feature_mutex); +- +- // Transmit 'get feature' request. +- int r = CHECK(ithc_dma_tx, ithc, code, 1, buf); +- if (!r) { +- r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature, +- !ithc->hid_get_feature_buf, msecs_to_jiffies(1000)); +- if (!r) +- r = -ETIMEDOUT; +- else if (r < 0) +- r = -EINTR; +- else +- r = 0; +- } +- +- // If everything went ok, the buffer has been filled with the response data. +- // Return the response size. +- mutex_lock(&ithc->hid_get_feature_mutex); +- ithc->hid_get_feature_buf = NULL; +- if (!r) +- r = ithc->hid_get_feature_size; +- mutex_unlock(&ithc->hid_get_feature_mutex); +- return r; +- } +- +- // 'Set feature', or 'output report'. These don't have a response. +- CHECK_RET(ithc_dma_tx, ithc, code, len, buf); +- return 0; +-} +- +-static struct hid_ll_driver ithc_ll_driver = { +- .start = ithc_hid_start, +- .stop = ithc_hid_stop, +- .open = ithc_hid_open, +- .close = ithc_hid_close, +- .parse = ithc_hid_parse, +- .raw_request = ithc_hid_raw_request, +-}; +- +-static void ithc_hid_devres_release(struct device *dev, void *res) +-{ +- struct hid_device **hidm = res; +- if (*hidm) +- hid_destroy_device(*hidm); +-} +- +-static int ithc_hid_init(struct ithc *ithc) +-{ +- struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); +- if (!hidm) +- return -ENOMEM; +- devres_add(&ithc->pci->dev, hidm); +- struct hid_device *hid = hid_allocate_device(); +- if (IS_ERR(hid)) +- return PTR_ERR(hid); +- *hidm = hid; +- +- strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); +- strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); +- hid->ll_driver = &ithc_ll_driver; +- hid->bus = BUS_PCI; +- hid->vendor = ithc->config.vendor_id; +- hid->product = ithc->config.product_id; +- hid->version = 0x100; +- hid->dev.parent = &ithc->pci->dev; +- hid->driver_data = ithc; +- +- ithc->hid = hid; +- return 0; +-} +- + // Interrupts/polling + +-static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t) +-{ +- struct ithc *ithc = container_of(t, struct ithc, activity_start_timer); +- ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC); +- return HRTIMER_NORESTART; +-} +- +-static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t) +-{ +- struct ithc *ithc = container_of(t, struct ithc, activity_end_timer); +- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); +- return HRTIMER_NORESTART; +-} +- +-void ithc_set_active(struct ithc *ithc, unsigned int duration_us) +-{ +- if (ithc_dma_latency_us < 0) +- return; +- // When CPU usage is very low, the CPU can enter various low power states (C2-C10). +- // This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be +- // set when this happens. The amount of truncated messages can become very high, resulting +- // in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency +- // QoS request to prevent the CPU from entering low power states during touch interactions. +- cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us); +- hrtimer_start_range_ns(&ithc->activity_end_timer, +- ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL); +-} +- +-static int ithc_set_device_enabled(struct ithc *ithc, bool enable) +-{ +- u32 x = ithc->config.touch_cfg = +- (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 | +- (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0); +- return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, +- offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); +-} +- + static void ithc_disable_interrupts(struct ithc *ithc) + { + writel(0, &ithc->regs->error_control); + bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); +- bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); +- bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); + bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); + } + + static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) + { +- writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA, ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, + &ithc->regs->dma_rx[channel].status); + } + +@@ -325,39 +128,22 @@ static void ithc_process(struct ithc *ithc) + { + ithc_log_regs(ithc); + ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back here, since ++ // the DMA transfer should be complete. ++ ithc_set_ltr_idle(ithc); ++ + bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; + bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; + +- // Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer +- ktime_t t = ktime_get(); +- ktime_t dt = ktime_sub(t, ithc->last_rx_time); +- if (rx0 || rx1) { +- ithc->last_rx_time = t; +- if (dt > ms_to_ktime(100)) { +- ithc->cur_rx_seq_count = 0; +- ithc->cur_rx_seq_errors = 0; +- } +- ithc->cur_rx_seq_count++; +- if (!ithc_use_polling && ithc_dma_latency_us >= 0) { +- // Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below) +- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); +- hrtimer_try_to_cancel(&ithc->activity_end_timer); +- } +- } +- + // Read and clear error bits + u32 err = readl(&ithc->regs->error_flags); + if (err) { + writel(err, &ithc->regs->error_flags); + if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) + pci_err(ithc->pci, "error flags: 0x%08x\n", err); +- if (err & ERROR_FLAG_DMA_RX_TIMEOUT) { +- // Only log an error if we see a significant number of these errors. +- ithc->cur_rx_seq_errors++; +- if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10) +- pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n", +- ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt)); +- } ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); + } + + // Process DMA rx +@@ -372,12 +158,6 @@ static void ithc_process(struct ithc *ithc) + ithc_dma_rx(ithc, 1); + } + +- // Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT +- if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) { +- ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us)); +- hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS); +- } +- + ithc_log_regs(ithc); + } + +@@ -403,12 +183,8 @@ static int ithc_poll_thread(void *arg) + ithc_process(ithc); + // Decrease polling interval to 20ms if we received data, otherwise slowly + // increase it up to 200ms. +- if (n != ithc->dma_rx[1].num_received) { +- ithc_set_active(ithc, 100 * USEC_PER_MSEC); +- sleep = 20; +- } else { +- sleep = min(200u, sleep + (sleep >> 4) + 1); +- } ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); + msleep_interruptible(sleep); + } + return 0; +@@ -431,73 +207,44 @@ static void ithc_disable(struct ithc *ithc) + + static int ithc_init_device(struct ithc *ithc) + { ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device + ithc_log_regs(ithc); + bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; + ithc_disable(ithc); + CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); +- +- // Since we don't yet know which SPI config the device wants, use default speed and mode +- // initially for reading config data. +- ithc_set_spi_config(ithc, 10, 0); +- +- // Setting the following bit seems to make reading the config more reliable. +- bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000); ++ ithc_log_regs(ithc); + + // If the device was previously enabled, wait a bit to make sure it's fully shut down. + if (was_enabled) + if (msleep_interruptible(100)) + return -EINTR; + +- // Take the touch device out of reset. +- bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); +- CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); +- for (int retries = 0; ; retries++) { +- ithc_log_regs(ithc); +- bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); +- if (!waitl(ithc, &ithc->regs->state, 0xf, 2)) +- break; +- if (retries > 5) { +- pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state)); +- return -ETIMEDOUT; +- } +- pci_warn(ithc->pci, "invalid state, retrying reset\n"); +- bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); +- if (msleep_interruptible(1000)) +- return -EINTR; +- } +- ithc_log_regs(ithc); ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 100us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 100 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); + +- // Waiting for the following status bit makes reading config much more reliable, +- // however the official driver does not seem to do this... +- CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4); ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); + +- // Read configuration data. +- for (int retries = 0; ; retries++) { +- ithc_log_regs(ithc); +- memset(&ithc->config, 0, sizeof(ithc->config)); +- CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config); +- u32 *p = (void *)&ithc->config; +- pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", +- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); +- if (ithc_is_config_valid(ithc)) +- break; +- if (retries > 10) { +- pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", +- ithc->config.device_id); +- return -EIO; +- } +- pci_warn(ithc->pci, "failed to read config, retrying\n"); +- if (msleep_interruptible(100)) +- return -EINTR; +- } +- ithc_log_regs(ithc); +- +- // Apply SPI config and enable touch device. +- CHECK_RET(ithc_set_spi_config, ithc, +- DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config), +- DEVCFG_SPI_MODE(ithc->config.spi_config)); +- CHECK_RET(ithc_set_device_enabled, ithc, true); +- ithc_log_regs(ithc); + return 0; + } + +@@ -527,11 +274,11 @@ static void ithc_stop(void *res) + CHECK(kthread_stop, ithc->poll_thread); + if (ithc->irq >= 0) + disable_irq(ithc->irq); +- CHECK(ithc_set_device_enabled, ithc, false); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); + ithc_disable(ithc); +- hrtimer_cancel(&ithc->activity_start_timer); +- hrtimer_cancel(&ithc->activity_end_timer); +- cpu_latency_qos_remove_request(&ithc->activity_qos); + + // Clear DMA config. + for (unsigned int i = 0; i < 2; i++) { +@@ -570,9 +317,6 @@ static int ithc_start(struct pci_dev *pci) + ithc->irq = -1; + ithc->pci = pci; + snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); +- init_waitqueue_head(&ithc->wait_hid_parse); +- init_waitqueue_head(&ithc->wait_hid_get_feature); +- mutex_init(&ithc->hid_get_feature_mutex); + pci_set_drvdata(pci, ithc); + CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); + if (ithc_log_regs_enabled) +@@ -596,6 +340,9 @@ static int ithc_start(struct pci_dev *pci) + + // Initialize THC and touch device. + CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); + CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups); + if (ithc_use_rx0) + CHECK_RET(ithc_dma_rx_init, ithc, 0); +@@ -603,18 +350,10 @@ static int ithc_start(struct pci_dev *pci) + CHECK_RET(ithc_dma_rx_init, ithc, 1); + CHECK_RET(ithc_dma_tx_init, ithc); + +- cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); +- hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); +- ithc->activity_start_timer.function = ithc_activity_start_timer_callback; +- hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +- ithc->activity_end_timer.function = ithc_activity_end_timer_callback; +- + // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are + // disabled BEFORE the buffers are freed. + CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); + +- CHECK_RET(ithc_hid_init, ithc); +- + // Start polling/IRQ. + if (ithc_use_polling) { + pci_info(pci, "using polling instead of irq\n"); +@@ -637,9 +376,11 @@ static int ithc_start(struct pci_dev *pci) + + // hid_add_device() can only be called after irq/polling is started and DMA is enabled, + // because it calls ithc_hid_parse() which reads the report descriptor via DMA. +- CHECK_RET(hid_add_device, ithc->hid); ++ CHECK_RET(hid_add_device, ithc->hid.dev); + +- CHECK(ithc_debug_init, ithc); ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); + + pci_dbg(pci, "started\n"); + return 0; +@@ -710,17 +451,20 @@ static struct pci_driver ithc_driver = { + .thaw = ithc_thaw, + .restore = ithc_restore, + }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, + //.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway + }; + + static int __init ithc_init(void) + { ++ ithc_debug_init_module(); + return pci_register_driver(&ithc_driver); + } + + static void __exit ithc_exit(void) + { + pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); + } + + module_init(ithc_init); +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..760e55ead078 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,578 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ if (cfg->has_read_opcode) { ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_single); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_dual); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_quad); ++ } ++ if (cfg->has_write_opcode) { ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_single); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_dual); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_quad); ++ } ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +index e058721886e3..c0f13506af20 100644 +--- a/drivers/hid/ithc/ithc-regs.c ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -22,46 +22,104 @@ void bitsb(__iomem u8 *reg, u8 mask, u8 val) + + int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) + { ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", + reg_num(reg), mask, val); + u32 x; + if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); + pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", + reg_num(reg), mask, val); + return -ETIMEDOUT; + } ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "done waiting\n"); + return 0; + } + + int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) + { ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", + reg_num(reg), mask, val); + u8 x; + if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); + pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", + reg_num(reg), mask, val); + return -ETIMEDOUT; + } ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "done waiting\n"); + return 0; + } + +-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode) ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) + { +- pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode); +- if (mode == 3) +- mode = 2; ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); + bitsl(&ithc->regs->spi_config, +- SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff), +- SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed)); ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); + return 0; + } + + int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) + { +- pci_dbg(ithc->pci, "SPI command %u, size %u, offset %u\n", command, size, offset); ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); + if (size > sizeof(ithc->regs->spi_cmd.data)) + return -EINVAL; + +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +index d4007d9e2bac..a9d236454644 100644 +--- a/drivers/hid/ithc/ithc-regs.h ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -1,14 +1,34 @@ + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ + #define CONTROL_QUIESCE BIT(1) + #define CONTROL_IS_QUIESCED BIT(2) + #define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) + #define CONTROL_READY BIT(29) + +-#define SPI_CONFIG_MODE(x) (((x) & 3) << 2) +-#define SPI_CONFIG_SPEED(x) (((x) & 7) << 4) +-#define SPI_CONFIG_UNKNOWN_18(x) (((x) & 3) << 18) +-#define SPI_CONFIG_SPEED2(x) (((x) & 0xf) << 20) // high bit = high speed mode? ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 + + #define ERROR_CONTROL_UNKNOWN_0 BIT(0) + #define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs +@@ -53,33 +73,71 @@ + #define DMA_TX_STATUS_UNKNOWN_2 BIT(2) + #define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? + ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ + #define DMA_RX_CONTROL_ENABLE BIT(0) + #define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? + #define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? +-#define DMA_RX_CONTROL_IRQ_UNKNOWN_4 BIT(4) // rx0 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only + #define DMA_RX_CONTROL_IRQ_DATA BIT(5) + ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? + #define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? + #define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices + + #define DMA_RX_WRAP_FLAG BIT(7) + + #define DMA_RX_STATUS_ERROR BIT(3) +-#define DMA_RX_STATUS_UNKNOWN_4 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) + #define DMA_RX_STATUS_HAVE_DATA BIT(5) + #define DMA_RX_STATUS_ENABLED BIT(8) + ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ + // COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. + #define COUNTER_RESET BIT(31) + + struct ithc_registers { +- /* 0000 */ u32 _unknown_0000[1024]; ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; + /* 1000 */ u32 _unknown_1000; + /* 1004 */ u32 _unknown_1004; + /* 1008 */ u32 control_bits; + /* 100c */ u32 _unknown_100c; + /* 1010 */ u32 spi_config; +- /* 1014 */ u32 _unknown_1014[3]; ++ /* 1014 */ u8 read_opcode; // maybe for header? ++ /* 1015 */ u8 read_opcode_quad; ++ /* 1016 */ u8 read_opcode_dual; ++ /* 1017 */ u8 read_opcode_single; ++ /* 1018 */ u8 write_opcode; // not used? ++ /* 1019 */ u8 write_opcode_quad; ++ /* 101a */ u8 write_opcode_dual; ++ /* 101b */ u8 write_opcode_single; ++ /* 101c */ u32 _unknown_101c; + /* 1020 */ u32 error_control; + /* 1024 */ u32 error_status; // write to clear + /* 1028 */ u32 error_flags; // write to clear +@@ -100,12 +158,19 @@ struct ithc_registers { + /* 109a */ u8 _unknown_109a; + /* 109b */ u8 num_prds; + /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; + } dma_tx; +- /* 10a0 */ u32 _unknown_10a0[7]; +- /* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; + /* 10c0 */ u32 _unknown_10c0[8]; + /* 10e0 */ u32 _unknown_10e0_counters[3]; +- /* 10ec */ u32 _unknown_10ec[5]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; + struct { + /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() + /* 1108/1208 */ u8 num_bufs; +@@ -120,70 +185,30 @@ struct ithc_registers { + /* 1118/1218 */ u64 _unknown_1118_guc_addr; + /* 1120/1220 */ u32 _unknown_1120_guc; + /* 1124/1224 */ u32 _unknown_1124_guc; +- /* 1128/1228 */ u32 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related ++ /* 1128/1228 */ u32 init_unknown; + /* 112c/122c */ u32 _unknown_112c; + /* 1130/1230 */ u64 _unknown_1130_guc_addr; + /* 1138/1238 */ u32 _unknown_1138_guc; + /* 113c/123c */ u32 _unknown_113c; + /* 1140/1240 */ u32 _unknown_1140_guc; +- /* 1144/1244 */ u32 _unknown_1144[23]; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; + /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; + /* 11b8/12b8 */ u32 _unknown_11b8[18]; + } dma_rx[2]; + }; + static_assert(sizeof(struct ithc_registers) == 0x1300); + +-#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) +-#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) +- +-#define DEVCFG_TOUCH_MASK 0x3f +-#define DEVCFG_TOUCH_ENABLE BIT(0) +-#define DEVCFG_TOUCH_UNKNOWN_1 BIT(1) +-#define DEVCFG_TOUCH_UNKNOWN_2 BIT(2) +-#define DEVCFG_TOUCH_UNKNOWN_3 BIT(3) +-#define DEVCFG_TOUCH_UNKNOWN_4 BIT(4) +-#define DEVCFG_TOUCH_UNKNOWN_5 BIT(5) +-#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) +- +-#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" +- +-#define DEVCFG_SPI_MAX_FREQ(x) (((x) >> 1) & 0xf) // high bit = use high speed mode? +-#define DEVCFG_SPI_MODE(x) (((x) >> 6) & 3) +-#define DEVCFG_SPI_UNKNOWN_8(x) (((x) >> 8) & 0x3f) +-#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat +-#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) +-#define DEVCFG_SPI_UNKNOWN_25 BIT(25) +-#define DEVCFG_SPI_UNKNOWN_26 BIT(26) +-#define DEVCFG_SPI_UNKNOWN_27 BIT(27) +-#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this +-#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? +- +-struct ithc_device_config { // (Example values are from an SP7+.) +- u32 _unknown_00; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) +- u32 _unknown_04; // 04 = 0x00000000 +- u32 dma_buf_sizes; // 08 = 0x000a00ff +- u32 touch_cfg; // 0c = 0x0000001c +- u32 _unknown_10; // 10 = 0x0000001c +- u32 device_id; // 14 = 0x43495424 = "$TIC" +- u32 spi_config; // 18 = 0xfda00a2e +- u16 vendor_id; // 1c = 0x045e = Microsoft Corp. +- u16 product_id; // 1e = 0x0c1a +- u32 revision; // 20 = 0x00000001 +- u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) +- u32 _unknown_28; // 28 = 0x00000000 +- u32 fw_mode; // 2c = 0x00000000 (for fw update?) +- u32 _unknown_30; // 30 = 0x00000000 +- u32 _unknown_34; // 34 = 0x0404035e (u8,u8,u8,u8 = version?) +- u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) +- u32 _unknown_3c; // 3c = 0x00000002 +-}; +- + void bitsl(__iomem u32 *reg, u32 mask, u32 val); + void bitsb(__iomem u8 *reg, u8 mask, u8 val); + #define bitsl_set(reg, x) bitsl(reg, x, x) + #define bitsb_set(reg, x) bitsb(reg, x, x) + int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); + int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); +-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); + int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); + +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +index 028e55a4ec53..e90c38044432 100644 +--- a/drivers/hid/ithc/ithc.h ++++ b/drivers/hid/ithc/ithc.h +@@ -1,20 +1,19 @@ + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + +-#include +-#include +-#include ++#include ++#include ++#include + #include ++#include + #include +-#include ++#include + #include + #include +-#include + #include + #include +-#include ++#include ++#include + #include +-#include +-#include + + #define DEVNAME "ithc" + #define DEVFULLNAME "Intel Touch Host Controller" +@@ -27,10 +26,37 @@ + + #define NUM_RX_BUF 16 + ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a ++ + struct ithc; + + #include "ithc-regs.h" ++#include "ithc-hid.h" + #include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" + + struct ithc { + char phys[32]; +@@ -38,30 +64,21 @@ struct ithc { + int irq; + struct task_struct *poll_thread; + +- struct pm_qos_request activity_qos; +- struct hrtimer activity_start_timer; +- struct hrtimer activity_end_timer; +- ktime_t last_rx_time; +- unsigned int cur_rx_seq_count; +- unsigned int cur_rx_seq_errors; +- +- struct hid_device *hid; +- bool hid_parse_done; +- wait_queue_head_t wait_hid_parse; +- wait_queue_head_t wait_hid_get_feature; +- struct mutex hid_get_feature_mutex; +- void *hid_get_feature_buf; +- size_t hid_get_feature_size; +- + struct ithc_registers __iomem *regs; + struct ithc_registers *prev_regs; // for debugging +- struct ithc_device_config config; + struct ithc_dma_rx dma_rx[2]; + struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; + }; + + int ithc_reset(struct ithc *ithc); +-void ithc_set_active(struct ithc *ithc, unsigned int duration_us); +-int ithc_debug_init(struct ithc *ithc); +-void ithc_log_regs(struct ithc *ithc); + +-- +2.44.1 + diff --git a/patches/6.9/0006-surface-sam.patch b/patches/6.9/0006-surface-sam.patch new file mode 100644 index 0000000000..01a3e1b153 --- /dev/null +++ b/patches/6.9/0006-surface-sam.patch @@ -0,0 +1,957 @@ +From 9740f9a56b1dff713a6bde51386ceece9bf9b37a Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 22 Oct 2023 14:57:11 +0200 +Subject: [PATCH 1/7] platform/surface: aggregator_registry: Add support for + Surface Laptop Go 3 + +Add SAM client device nodes for the Surface Laptop Go 3. It seems to use +the same SAM client devices as the Surface Laptop Go 1 and 2, so re-use +their node group. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 035d6b4105cd..74688a2ed4b2 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -374,6 +374,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Laptop Go 2 */ + { "MSHW0290", (unsigned long)ssam_node_group_slg1 }, + ++ /* Surface Laptop Go 3 */ ++ { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, ++ + /* Surface Laptop Studio */ + { "MSHW0123", (unsigned long)ssam_node_group_sls }, + +-- +2.44.1 + + +From 3bd7bc9cf8aa02303245ed2e6a18d86d8bd8ff80 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Mon, 20 Nov 2023 19:47:00 +0100 +Subject: [PATCH 2/7] platform/surface: aggregator_registry: Add support for + Surface Laptop Studio 2 + +Add SAM client device nodes for the Surface Laptop Studio 2 (SLS2). The +SLS2 is quite similar to the SLS1, but it does not provide the touchpad +as a SAM-HID device. Therefore, add a new node group for the SLS2 and +update the comments accordingly + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + .../surface/surface_aggregator_registry.c | 25 ++++++++++++++++--- + 1 file changed, 21 insertions(+), 4 deletions(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 74688a2ed4b2..f02a933160ff 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -253,8 +253,8 @@ static const struct software_node *ssam_node_group_sl5[] = { + NULL, + }; + +-/* Devices for Surface Laptop Studio. */ +-static const struct software_node *ssam_node_group_sls[] = { ++/* Devices for Surface Laptop Studio 1. */ ++static const struct software_node *ssam_node_group_sls1[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +@@ -269,6 +269,20 @@ static const struct software_node *ssam_node_group_sls[] = { + NULL, + }; + ++/* Devices for Surface Laptop Studio 2. */ ++static const struct software_node *ssam_node_group_sls2[] = { ++ &ssam_node_root, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ &ssam_node_tmp_pprof, ++ &ssam_node_pos_tablet_switch, ++ &ssam_node_hid_sam_keyboard, ++ &ssam_node_hid_sam_penstash, ++ &ssam_node_hid_sam_sensors, ++ &ssam_node_hid_sam_ucm_ucsi, ++ NULL, ++}; ++ + /* Devices for Surface Laptop Go. */ + static const struct software_node *ssam_node_group_slg1[] = { + &ssam_node_root, +@@ -377,8 +391,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Laptop Go 3 */ + { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, + +- /* Surface Laptop Studio */ +- { "MSHW0123", (unsigned long)ssam_node_group_sls }, ++ /* Surface Laptop Studio 1 */ ++ { "MSHW0123", (unsigned long)ssam_node_group_sls1 }, ++ ++ /* Surface Laptop Studio 2 */ ++ { "MSHW0360", (unsigned long)ssam_node_group_sls2 }, + + { }, + }; +-- +2.44.1 + + +From 04d066bc571f06c406ee0837e3db5dfedbba7859 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 30 Dec 2023 18:07:54 +0100 +Subject: [PATCH 3/7] hwmon: Add thermal sensor driver for Surface Aggregator + Module + +Some of the newer Microsoft Surface devices (such as the Surface Book +3 and Pro 9) have thermal sensors connected via the Surface Aggregator +Module (the embedded controller on those devices). Add a basic driver +to read out the temperature values of those sensors. + +Link: https://github.com/linux-surface/surface-aggregator-module/issues/59 +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/hwmon/Kconfig | 10 +++ + drivers/hwmon/Makefile | 1 + + drivers/hwmon/surface_temp.c | 165 +++++++++++++++++++++++++++++++++++ + 3 files changed, 176 insertions(+) + create mode 100644 drivers/hwmon/surface_temp.c + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 83945397b6eb..338ef73c96a3 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -2070,6 +2070,16 @@ config SENSORS_SURFACE_FAN + + Select M or Y here, if you want to be able to read the fan's speed. + ++config SENSORS_SURFACE_TEMP ++ tristate "Microsoft Surface Thermal Sensor Driver" ++ depends on SURFACE_AGGREGATOR ++ help ++ Driver for monitoring thermal sensors connected via the Surface ++ Aggregator Module (embedded controller) on Microsoft Surface devices. ++ ++ This driver can also be built as a module. If so, the module ++ will be called surface_temp. ++ + config SENSORS_ADC128D818 + tristate "Texas Instruments ADC128D818" + depends on I2C +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 5c31808f6378..de8bc99719e6 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -208,6 +208,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o + obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o + obj-$(CONFIG_SENSORS_STTS751) += stts751.o + obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o ++obj-$(CONFIG_SENSORS_SURFACE_TEMP)+= surface_temp.o + obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o + obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o + obj-$(CONFIG_SENSORS_TC74) += tc74.o +diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c +new file mode 100644 +index 000000000000..48c3e826713f +--- /dev/null ++++ b/drivers/hwmon/surface_temp.c +@@ -0,0 +1,165 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Thermal sensor subsystem driver for Surface System Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2022-2023 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++/* -- SAM interface. -------------------------------------------------------- */ ++ ++SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x04, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x01, ++}); ++ ++static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors) ++{ ++ __le16 sensors_le; ++ int status; ++ ++ status = __ssam_tmp_get_available_sensors(sdev, &sensors_le); ++ if (status) ++ return status; ++ ++ *sensors = le16_to_cpu(sensors_le); ++ return 0; ++} ++ ++static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temperature) ++{ ++ __le16 temp_le; ++ int status; ++ ++ status = __ssam_tmp_get_temperature(sdev->ctrl, sdev->uid.target, iid, &temp_le); ++ if (status) ++ return status; ++ ++ /* Convert 1/10 °K to 1/1000 °C */ ++ *temperature = (le16_to_cpu(temp_le) - 2731) * 100L; ++ return 0; ++} ++ ++ ++/* -- Driver.---------------------------------------------------------------- */ ++ ++struct ssam_temp { ++ struct ssam_device *sdev; ++ s16 sensors; ++}; ++ ++static umode_t ssam_temp_hwmon_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct ssam_temp *ssam_temp = data; ++ ++ if (!(ssam_temp->sensors & BIT(channel))) ++ return 0; ++ ++ return 0444; ++} ++ ++static int ssam_temp_hwmon_read(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, long *value) ++{ ++ const struct ssam_temp *ssam_temp = dev_get_drvdata(dev); ++ ++ return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value); ++} ++ ++static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = { ++ HWMON_CHANNEL_INFO(chip, ++ HWMON_C_REGISTER_TZ), ++ /* We have at most 16 thermal sensor channels. */ ++ HWMON_CHANNEL_INFO(temp, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT), ++ NULL ++}; ++ ++static const struct hwmon_ops ssam_temp_hwmon_ops = { ++ .is_visible = ssam_temp_hwmon_is_visible, ++ .read = ssam_temp_hwmon_read, ++}; ++ ++static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = { ++ .ops = &ssam_temp_hwmon_ops, ++ .info = ssam_temp_hwmon_info, ++}; ++ ++static int ssam_temp_probe(struct ssam_device *sdev) ++{ ++ struct ssam_temp *ssam_temp; ++ struct device *hwmon_dev; ++ s16 sensors; ++ int status; ++ ++ status = ssam_tmp_get_available_sensors(sdev, &sensors); ++ if (status) ++ return status; ++ ++ ssam_temp = devm_kzalloc(&sdev->dev, sizeof(*ssam_temp), GFP_KERNEL); ++ if (!ssam_temp) ++ return -ENOMEM; ++ ++ ssam_temp->sdev = sdev; ++ ssam_temp->sensors = sensors; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev, ++ "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, ++ NULL); ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ return 0; ++} ++ ++static const struct ssam_device_id ssam_temp_match[] = { ++ { SSAM_SDEV(TMP, SAM, 0x00, 0x02) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, ssam_temp_match); ++ ++static struct ssam_device_driver ssam_temp = { ++ .probe = ssam_temp_probe, ++ .match_table = ssam_temp_match, ++ .driver = { ++ .name = "surface_temp", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(ssam_temp); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.44.1 + + +From f97fa8fb9a6a94abd17c9fbc3fa3c719e6012ca8 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 30 Dec 2023 18:12:23 +0100 +Subject: [PATCH 4/7] hwmon: surface_temp: Add support for sensor names + +The thermal subsystem of the Surface Aggregator Module allows us to +query the names of the respective thermal sensors. Forward those to +userspace. + +Signed-off-by: Ivor Wanders +Co-Developed-by: Maximilian Luz +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/hwmon/surface_temp.c | 113 +++++++++++++++++++++++++++++------ + 1 file changed, 96 insertions(+), 17 deletions(-) + +diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c +index 48c3e826713f..4c08926139db 100644 +--- a/drivers/hwmon/surface_temp.c ++++ b/drivers/hwmon/surface_temp.c +@@ -17,6 +17,27 @@ + + /* -- SAM interface. -------------------------------------------------------- */ + ++/* ++ * Available sensors are indicated by a 16-bit bitfield, where a 1 marks the ++ * presence of a sensor. So we have at most 16 possible sensors/channels. ++ */ ++#define SSAM_TMP_SENSOR_MAX_COUNT 16 ++ ++/* ++ * All names observed so far are 6 characters long, but there's only ++ * zeros after the name, so perhaps they can be longer. This number reflects ++ * the maximum zero-padded space observed in the returned buffer. ++ */ ++#define SSAM_TMP_SENSOR_NAME_LENGTH 18 ++ ++struct ssam_tmp_get_name_rsp { ++ __le16 unknown1; ++ char unknown2; ++ char name[SSAM_TMP_SENSOR_NAME_LENGTH]; ++} __packed; ++ ++static_assert(sizeof(struct ssam_tmp_get_name_rsp) == 21); ++ + SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, { + .target_category = SSAM_SSH_TC_TMP, + .command_id = 0x04, +@@ -27,6 +48,11 @@ SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, { + .command_id = 0x01, + }); + ++SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_name, struct ssam_tmp_get_name_rsp, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x0e, ++}); ++ + static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors) + { + __le16 sensors_le; +@@ -54,12 +80,37 @@ static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temp + return 0; + } + ++static int ssam_tmp_get_name(struct ssam_device *sdev, u8 iid, char *buf, size_t buf_len) ++{ ++ struct ssam_tmp_get_name_rsp name_rsp; ++ int status; ++ ++ status = __ssam_tmp_get_name(sdev->ctrl, sdev->uid.target, iid, &name_rsp); ++ if (status) ++ return status; ++ ++ /* ++ * This should not fail unless the name in the returned struct is not ++ * null-terminated or someone changed something in the struct ++ * definitions above, since our buffer and struct have the same ++ * capacity by design. So if this fails blow this up with a warning. ++ * Since the more likely cause is that the returned string isn't ++ * null-terminated, we might have received garbage (as opposed to just ++ * an incomplete string), so also fail the function. ++ */ ++ status = strscpy(buf, name_rsp.name, buf_len); ++ WARN_ON(status < 0); ++ ++ return status < 0 ? status : 0; ++} ++ + + /* -- Driver.---------------------------------------------------------------- */ + + struct ssam_temp { + struct ssam_device *sdev; + s16 sensors; ++ char names[SSAM_TMP_SENSOR_MAX_COUNT][SSAM_TMP_SENSOR_NAME_LENGTH]; + }; + + static umode_t ssam_temp_hwmon_is_visible(const void *data, +@@ -83,33 +134,47 @@ static int ssam_temp_hwmon_read(struct device *dev, + return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value); + } + ++static int ssam_temp_hwmon_read_string(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, const char **str) ++{ ++ const struct ssam_temp *ssam_temp = dev_get_drvdata(dev); ++ ++ *str = ssam_temp->names[channel]; ++ return 0; ++} ++ + static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_REGISTER_TZ), +- /* We have at most 16 thermal sensor channels. */ ++ /* ++ * We have at most SSAM_TMP_SENSOR_MAX_COUNT = 16 thermal sensor ++ * channels. ++ */ + HWMON_CHANNEL_INFO(temp, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT), ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL), + NULL + }; + + static const struct hwmon_ops ssam_temp_hwmon_ops = { + .is_visible = ssam_temp_hwmon_is_visible, + .read = ssam_temp_hwmon_read, ++ .read_string = ssam_temp_hwmon_read_string, + }; + + static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = { +@@ -122,6 +187,7 @@ static int ssam_temp_probe(struct ssam_device *sdev) + struct ssam_temp *ssam_temp; + struct device *hwmon_dev; + s16 sensors; ++ int channel; + int status; + + status = ssam_tmp_get_available_sensors(sdev, &sensors); +@@ -135,6 +201,19 @@ static int ssam_temp_probe(struct ssam_device *sdev) + ssam_temp->sdev = sdev; + ssam_temp->sensors = sensors; + ++ /* Retrieve the name for each available sensor. */ ++ for (channel = 0; channel < SSAM_TMP_SENSOR_MAX_COUNT; channel++) ++ { ++ if (!(sensors & BIT(channel))) ++ continue; ++ ++ status = ssam_tmp_get_name(sdev, channel + 1, ++ ssam_temp->names[channel], ++ SSAM_TMP_SENSOR_NAME_LENGTH); ++ if (status) ++ return status; ++ } ++ + hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev, + "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, + NULL); +-- +2.44.1 + + +From 680b16d7ac234ebc3885a898d69105cc00da1c49 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 30 Dec 2023 18:21:12 +0100 +Subject: [PATCH 5/7] platform/surface: aggregator_registry: Add support for + thermal sensors on the Surface Pro 9 + +The Surface Pro 9 has thermal sensors connected via the Surface +Aggregator Module. Add a device node to support those. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index f02a933160ff..67686042e009 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = { + .parent = &ssam_node_root, + }; + ++/* Thermal sensors. */ ++static const struct software_node ssam_node_tmp_sensors = { ++ .name = "ssam:01:03:01:00:02", ++ .parent = &ssam_node_root, ++}; ++ + /* Fan speed function. */ + static const struct software_node ssam_node_fan_speed = { + .name = "ssam:01:05:01:01:01", +@@ -325,6 +331,7 @@ static const struct software_node *ssam_node_group_sp9[] = { + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_tmp_pprof, ++ &ssam_node_tmp_sensors, + &ssam_node_fan_speed, + &ssam_node_pos_tablet_switch, + &ssam_node_hid_kip_keyboard, +-- +2.44.1 + + +From 500f45035aa04b231d9b7406a0e6f9ade8d6afb0 Mon Sep 17 00:00:00 2001 +From: Ivor Wanders +Date: Sat, 16 Dec 2023 15:56:39 -0500 +Subject: [PATCH 6/7] platform/surface: platform_profile: add fan profile + switching + +Change naming from tmp to platform profile to clarify the module may +interact with both the TMP and FAN subystems. Add functionality that +switches the fan profile when the platform profile is changed. + +Signed-off-by: Ivor Wanders +Patchset: surface-sam +--- + .../surface/surface_aggregator_registry.c | 38 +++++--- + .../surface/surface_platform_profile.c | 86 ++++++++++++++++--- + 2 files changed, 100 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 67686042e009..058b6654a91a 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -68,8 +68,8 @@ static const struct software_node ssam_node_bat_sb3base = { + .parent = &ssam_node_hub_base, + }; + +-/* Platform profile / performance-mode device. */ +-static const struct software_node ssam_node_tmp_pprof = { ++/* Platform profile / performance-mode device without a fan. */ ++static const struct software_node ssam_node_tmp_perf_profile = { + .name = "ssam:01:03:01:00:01", + .parent = &ssam_node_root, + }; +@@ -86,6 +86,20 @@ static const struct software_node ssam_node_fan_speed = { + .parent = &ssam_node_root, + }; + ++/* Platform profile / performance-mode device with a fan, such that ++ * the fan controller profile can also be switched. ++ */ ++static const struct property_entry ssam_node_tmp_perf_profile_has_fan[] = { ++ PROPERTY_ENTRY_BOOL("has_fan"), ++ { } ++}; ++ ++static const struct software_node ssam_node_tmp_perf_profile_with_fan = { ++ .name = "ssam:01:03:01:00:01", ++ .parent = &ssam_node_root, ++ .properties = ssam_node_tmp_perf_profile_has_fan, ++}; ++ + /* Tablet-mode switch via KIP subsystem. */ + static const struct software_node ssam_node_kip_tablet_switch = { + .name = "ssam:01:0e:01:00:01", +@@ -214,7 +228,7 @@ static const struct software_node ssam_node_pos_tablet_switch = { + */ + static const struct software_node *ssam_node_group_gen5[] = { + &ssam_node_root, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + NULL, + }; + +@@ -225,7 +239,7 @@ static const struct software_node *ssam_node_group_sb3[] = { + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_bat_sb3base, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + &ssam_node_bas_dtx, + &ssam_node_hid_base_keyboard, + &ssam_node_hid_base_touchpad, +@@ -239,7 +253,7 @@ static const struct software_node *ssam_node_group_sl3[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + &ssam_node_hid_main_keyboard, + &ssam_node_hid_main_touchpad, + &ssam_node_hid_main_iid5, +@@ -251,7 +265,7 @@ static const struct software_node *ssam_node_group_sl5[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + &ssam_node_hid_main_keyboard, + &ssam_node_hid_main_touchpad, + &ssam_node_hid_main_iid5, +@@ -264,7 +278,7 @@ static const struct software_node *ssam_node_group_sls1[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + &ssam_node_pos_tablet_switch, + &ssam_node_hid_sam_keyboard, + &ssam_node_hid_sam_penstash, +@@ -280,7 +294,7 @@ static const struct software_node *ssam_node_group_sls2[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + &ssam_node_pos_tablet_switch, + &ssam_node_hid_sam_keyboard, + &ssam_node_hid_sam_penstash, +@@ -294,7 +308,7 @@ static const struct software_node *ssam_node_group_slg1[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + NULL, + }; + +@@ -303,7 +317,7 @@ static const struct software_node *ssam_node_group_sp7[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + NULL, + }; + +@@ -313,7 +327,7 @@ static const struct software_node *ssam_node_group_sp8[] = { + &ssam_node_hub_kip, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile, + &ssam_node_kip_tablet_switch, + &ssam_node_hid_kip_keyboard, + &ssam_node_hid_kip_penstash, +@@ -330,7 +344,7 @@ static const struct software_node *ssam_node_group_sp9[] = { + &ssam_node_hub_kip, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile_with_fan, + &ssam_node_tmp_sensors, + &ssam_node_fan_speed, + &ssam_node_pos_tablet_switch, +diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c +index a5a3941b3f43..e54d0a8f7daa 100644 +--- a/drivers/platform/surface/surface_platform_profile.c ++++ b/drivers/platform/surface/surface_platform_profile.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0+ + /* + * Surface Platform Profile / Performance Mode driver for Surface System +- * Aggregator Module (thermal subsystem). ++ * Aggregator Module (thermal and fan subsystem). + * + * Copyright (C) 2021-2022 Maximilian Luz + */ +@@ -14,6 +14,7 @@ + + #include + ++// Enum for the platform performance profile sent to the TMP module. + enum ssam_tmp_profile { + SSAM_TMP_PROFILE_NORMAL = 1, + SSAM_TMP_PROFILE_BATTERY_SAVER = 2, +@@ -21,15 +22,26 @@ enum ssam_tmp_profile { + SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4, + }; + ++// Enum for the fan profile sent to the FAN module. This fan profile is ++// only sent to the EC if the 'has_fan' property is set. The integers are ++// not a typo, they differ from the performance profile indices. ++enum ssam_fan_profile { ++ SSAM_FAN_PROFILE_NORMAL = 2, ++ SSAM_FAN_PROFILE_BATTERY_SAVER = 1, ++ SSAM_FAN_PROFILE_BETTER_PERFORMANCE = 3, ++ SSAM_FAN_PROFILE_BEST_PERFORMANCE = 4, ++}; ++ + struct ssam_tmp_profile_info { + __le32 profile; + __le16 unknown1; + __le16 unknown2; + } __packed; + +-struct ssam_tmp_profile_device { ++struct ssam_platform_profile_device { + struct ssam_device *sdev; + struct platform_profile_handler handler; ++ bool has_fan; + }; + + SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, { +@@ -42,6 +54,13 @@ SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, { + .command_id = 0x03, + }); + ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_fan_profile_set, char, { ++ .target_category = SSAM_SSH_TC_FAN, ++ .target_id = SSAM_SSH_TID_SAM, ++ .command_id = 0x0e, ++ .instance_id = 0x01, ++}); ++ + static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p) + { + struct ssam_tmp_profile_info info; +@@ -62,7 +81,14 @@ static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile + return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le); + } + +-static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p) ++static int ssam_fan_profile_set(struct ssam_device *sdev, enum ssam_fan_profile p) ++{ ++ char profile = p; ++ ++ return ssam_retry(__ssam_fan_profile_set, sdev->ctrl, &profile); ++} ++ ++static int convert_ssam_tmp_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p) + { + switch (p) { + case SSAM_TMP_PROFILE_NORMAL: +@@ -83,7 +109,8 @@ static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profi + } + } + +-static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p) ++ ++static int convert_profile_to_ssam_tmp(struct ssam_device *sdev, enum platform_profile_option p) + { + switch (p) { + case PLATFORM_PROFILE_LOW_POWER: +@@ -105,20 +132,42 @@ static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profi + } + } + ++static int convert_profile_to_ssam_fan(struct ssam_device *sdev, enum platform_profile_option p) ++{ ++ switch (p) { ++ case PLATFORM_PROFILE_LOW_POWER: ++ return SSAM_FAN_PROFILE_BATTERY_SAVER; ++ ++ case PLATFORM_PROFILE_BALANCED: ++ return SSAM_FAN_PROFILE_NORMAL; ++ ++ case PLATFORM_PROFILE_BALANCED_PERFORMANCE: ++ return SSAM_FAN_PROFILE_BETTER_PERFORMANCE; ++ ++ case PLATFORM_PROFILE_PERFORMANCE: ++ return SSAM_FAN_PROFILE_BEST_PERFORMANCE; ++ ++ default: ++ /* This should have already been caught by platform_profile_store(). */ ++ WARN(true, "unsupported platform profile"); ++ return -EOPNOTSUPP; ++ } ++} ++ + static int ssam_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) + { +- struct ssam_tmp_profile_device *tpd; ++ struct ssam_platform_profile_device *tpd; + enum ssam_tmp_profile tp; + int status; + +- tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); ++ tpd = container_of(pprof, struct ssam_platform_profile_device, handler); + + status = ssam_tmp_profile_get(tpd->sdev, &tp); + if (status) + return status; + +- status = convert_ssam_to_profile(tpd->sdev, tp); ++ status = convert_ssam_tmp_to_profile(tpd->sdev, tp); + if (status < 0) + return status; + +@@ -129,21 +178,32 @@ static int ssam_platform_profile_get(struct platform_profile_handler *pprof, + static int ssam_platform_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) + { +- struct ssam_tmp_profile_device *tpd; ++ struct ssam_platform_profile_device *tpd; + int tp; + +- tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); ++ tpd = container_of(pprof, struct ssam_platform_profile_device, handler); + +- tp = convert_profile_to_ssam(tpd->sdev, profile); ++ tp = convert_profile_to_ssam_tmp(tpd->sdev, profile); + if (tp < 0) + return tp; + +- return ssam_tmp_profile_set(tpd->sdev, tp); ++ tp = ssam_tmp_profile_set(tpd->sdev, tp); ++ if (tp < 0) ++ return tp; ++ ++ if (tpd->has_fan) { ++ tp = convert_profile_to_ssam_fan(tpd->sdev, profile); ++ if (tp < 0) ++ return tp; ++ tp = ssam_fan_profile_set(tpd->sdev, tp); ++ } ++ ++ return tp; + } + + static int surface_platform_profile_probe(struct ssam_device *sdev) + { +- struct ssam_tmp_profile_device *tpd; ++ struct ssam_platform_profile_device *tpd; + + tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL); + if (!tpd) +@@ -154,6 +214,8 @@ static int surface_platform_profile_probe(struct ssam_device *sdev) + tpd->handler.profile_get = ssam_platform_profile_get; + tpd->handler.profile_set = ssam_platform_profile_set; + ++ tpd->has_fan = device_property_read_bool(&sdev->dev, "has_fan"); ++ + set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices); + set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices); + set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices); +-- +2.44.1 + + +From 0826fa5b802cae18967e733b525ea175cace518d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 19 Apr 2024 20:41:47 +0200 +Subject: [PATCH 7/7] platform/surface: aggregator: Fix warning when controller + is destroyed in probe + +There is a small window in ssam_serial_hub_probe() where the controller +is initialized but has not been started yet. Specifically, between +ssam_controller_init() and ssam_controller_start(). Any failure in this +window, for example caused by a failure of serdev_device_open(), +currently results in an incorrect warning being emitted. + +In particular, any failure in this window results in the controller +being destroyed via ssam_controller_destroy(). This function checks the +state of the controller and, in an attempt to validate that the +controller has been cleanly shut down before we try and deallocate any +resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. + +However, since we have only just initialized the controller and have not +yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this +is the only point at which the controller has this state, as it will +change after we start the controller with ssam_controller_start() and +never revert back. Further, at this point no communication has taken +place and the sender and receiver threads have not been started yet (and +we may not even have an open serdev device either). + +Therefore, it is perfectly safe to call ssam_controller_destroy() with a +state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the +warning currently being emitted is incorrect. Fix it by extending the +check. + +Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") +Signed-off-by: Maximilian Luz +--- + drivers/platform/surface/aggregator/controller.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c +index 7fc602e01487..7e89f547999b 100644 +--- a/drivers/platform/surface/aggregator/controller.c ++++ b/drivers/platform/surface/aggregator/controller.c +@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) + if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) + return; + +- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); ++ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && ++ ctrl->state != SSAM_CONTROLLER_INITIALIZED); + + /* + * Note: New events could still have been received after the previous +-- +2.44.1 + diff --git a/patches/6.9/0007-surface-sam-over-hid.patch b/patches/6.9/0007-surface-sam-over-hid.patch new file mode 100644 index 0000000000..7b76987d92 --- /dev/null +++ b/patches/6.9/0007-surface-sam-over-hid.patch @@ -0,0 +1,337 @@ +From 8586d7576a7338e5811b3eb86bfac1bf7b434e06 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH 1/2] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index d6037a328669..a290ebc77aea 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -628,6 +628,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret = AE_OK; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -729,6 +751,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.44.1 + + +From c9ed90b27e8847666c754779ba2cbcd11a53efc6 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH 2/2] platform/surface: Add driver for Surface Book 1 dGPU + switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 162 ++++++++++++++++++ + 3 files changed, 170 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..8b816ed8f35c +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,162 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef pr_fmt ++#undef pr_fmt ++#endif ++#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ ++ ++ ++static const guid_t dgpu_sw_guid = GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *ret; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ ret = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!ret) ++ return -EINVAL; ++ ++ ACPI_FREE(ret); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(void) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ pr_err("failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ if (buf.pointer) ++ ACPI_FREE(buf.pointer); ++ ++ pr_info("turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(void) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ pr_err("failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ if (buf.pointer) ++ ACPI_FREE(buf.pointer); ++ ++ pr_info("turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int status, value; ++ ++ status = kstrtoint(buf, 0, &value); ++ if (status < 0) ++ return status; ++ ++ if (value != 1) ++ return -EINVAL; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(); ++ else ++ status = sb1_dgpu_sw_hgof(); ++ ++ return status < 0 ? status : len; ++} ++ ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL, ++}; ++ ++static const struct attribute_group sb1_dgpu_sw_attr_group = { ++ .attrs = sb1_dgpu_sw_attrs, ++}; ++ ++ ++static int sb1_dgpu_sw_probe(struct platform_device *pdev) ++{ ++ return sysfs_create_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); ++} ++ ++static int sb1_dgpu_sw_remove(struct platform_device *pdev) ++{ ++ sysfs_remove_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); ++ return 0; ++} ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .probe = sb1_dgpu_sw_probe, ++ .remove = sb1_dgpu_sw_remove, ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.44.1 + diff --git a/patches/6.9/0008-surface-button.patch b/patches/6.9/0008-surface-button.patch new file mode 100644 index 0000000000..bcda2d88da --- /dev/null +++ b/patches/6.9/0008-surface-button.patch @@ -0,0 +1,151 @@ +From 4d98c340e8182909ec39477fb382e22952f557c0 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH 1/2] Input: soc_button_array - support AMD variant Surface + devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index f6d060377d18..b8603f74eb28 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero ++ bool exists; + +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; +- +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); +- +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.44.1 + + +From cf5cec4b4b5d7dfe98710b232c9e1227599ada1a Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH 2/2] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero + +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); +- +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.44.1 + diff --git a/patches/6.9/0009-surface-typecover.patch b/patches/6.9/0009-surface-typecover.patch new file mode 100644 index 0000000000..1b3dc2248b --- /dev/null +++ b/patches/6.9/0009-surface-typecover.patch @@ -0,0 +1,575 @@ +From ce569f6ee0bb24bfe2efc37a8aadc287aef1c5eb Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH 1/3] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index b4783574b8e6..360970620589 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.44.1 + + +From 6ec5d78cb24e61fe7601c40032bc1a713a87ad42 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH 2/3] hid/multitouch: Turn off Type Cover keyboard backlight + when suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 04a014cd2a2f..89c9b00e6371 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -34,7 +34,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -168,6 +175,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + + #define MT_DEFAULT_MAXCONTACT 10 + #define MT_MAX_MAXCONTACT 250 +@@ -396,6 +406,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_SEPARATE_APP_REPORT, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1720,6 +1740,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1743,6 +1826,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1781,15 +1867,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1839,6 +1929,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2229,6 +2320,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.44.1 + + +From a62411b28850e81c704a44339d15e29049310efb Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH 3/3] hid/multitouch: Add support for surface pro type cover + tablet switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 89c9b00e6371..be131488161c 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -408,6 +411,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1389,6 +1393,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1416,6 +1423,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1437,6 +1459,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1444,6 +1467,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1453,11 +1489,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1610,6 +1656,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1658,6 +1740,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1740,30 +1829,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1772,8 +1837,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1907,13 +1973,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1922,12 +1999,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.44.1 + diff --git a/patches/6.9/0010-surface-shutdown.patch b/patches/6.9/0010-surface-shutdown.patch new file mode 100644 index 0000000000..2e1a027b8d --- /dev/null +++ b/patches/6.9/0010-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 045c80e1a685de8aa6a306600e5715c320ba3de5 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index af2996d0d17f..3ce0fb61257d 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index eff7f5df08e2..d1cb4ff3ebc5 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6253,3 +6253,39 @@ static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev) + pdev->d3cold_delay = 1000; + } + DECLARE_PCI_FIXUP_FINAL(0x5555, 0x0004, pci_fixup_d3cold_delay_1sec); ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 16493426a04f..0eb821624056 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -465,6 +465,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.44.1 + diff --git a/patches/6.9/0011-surface-gpe.patch b/patches/6.9/0011-surface-gpe.patch new file mode 100644 index 0000000000..3ace4d2c61 --- /dev/null +++ b/patches/6.9/0011-surface-gpe.patch @@ -0,0 +1,51 @@ +From f5431b805f716b745dd631d8e4919c03ad0a7e76 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index 62fd4004db31..103fc4468262 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.44.1 + diff --git a/patches/6.9/0012-cameras.patch b/patches/6.9/0012-cameras.patch new file mode 100644 index 0000000000..6d13cf3cf2 --- /dev/null +++ b/patches/6.9/0012-cameras.patch @@ -0,0 +1,790 @@ +From 9bb6322136d802c4a42df455f0bce54e1691a206 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH 01/11] ACPI: delay enumeration of devices with a _DEP pointing + to an INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index d1464324de95..5d865a34dd9d 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2181,6 +2181,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.44.1 + + +From e2f50feee091c07295594805eabe9be3b124352c Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH 02/11] iommu: intel-ipu: use IOMMU passthrough mode for Intel + IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 61bc54299a59..a61af0f4e9fc 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -44,6 +44,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -227,12 +234,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -2409,6 +2418,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2711,6 +2723,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4884,6 +4899,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4931,6 +4958,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.44.1 + + +From d2fd30586a30e3d32063ea33d50d33919ce521c7 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH 03/11] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 1e107fd49f82..e3e1696e7f0e 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.44.1 + + +From 2d9a4443e87df40907e443e63435ead7a3bfe88f Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH 04/11] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 07b302e09340..1d3097bc7e48 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity = GPIO_ACTIVE_HIGH; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) +-- +2.44.1 + + +From 1aadc03192c2591c7b07470948df39a1792f2f70 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH 05/11] media: i2c: Clarify that gain is Analogue gain in + OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.44.1 + + +From 1a66fcaa0d09216340a495e1e87900833a456f78 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH 06/11] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index 3ec323bd528b..b55570a0142c 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -796,6 +796,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index 89c7192148df..44eca113e772 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.44.1 + + +From ba1f6c4984abef2e5d47f07da45018980d5dabc0 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH 07/11] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index e3e1696e7f0e..423dc555093f 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.44.1 + + +From f9b20b31ae21ea4762c963a5fb1e6c01bde3e726 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH 08/11] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.44.1 + + +From adecf115a9a05225e4eb55172f7d0160a8e50b8f Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH 09/11] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 05e6af88b88c..c120eb0b5aa8 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -909,6 +909,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index effdfc6f1e95..6ce609b2cdac 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -86,6 +86,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.44.1 + + +From 3bcfebe8b0d2ddccbabcfd43a083beec6cc896fe Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Sat, 3 Feb 2024 12:59:53 +0900 +Subject: [PATCH 10/11] media: staging: ipu3-imgu: Fix multiple calls of + s_stream on stream stop + +Adapt to 009905e "media: v4l2-subdev: Document and enforce .s_stream() requirements" + +Patchset: cameras +--- + drivers/staging/media/ipu3/ipu3-v4l2.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c +index 3df58eb3e882..81aff2d5d898 100644 +--- a/drivers/staging/media/ipu3/ipu3-v4l2.c ++++ b/drivers/staging/media/ipu3/ipu3-v4l2.c +@@ -538,18 +538,18 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq) + + WARN_ON(!node->enabled); + +- pipe = node->pipe; +- dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); +- imgu_pipe = &imgu->imgu_pipe[pipe]; +- r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); +- if (r) +- dev_err(&imgu->pci_dev->dev, +- "failed to stop subdev streaming\n"); +- + mutex_lock(&imgu->streaming_lock); + /* Was this the first node with streaming disabled? */ + if (imgu->streaming && imgu_all_nodes_streaming(imgu, node)) { + /* Yes, really stop streaming now */ ++ pipe = node->pipe; ++ dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); ++ imgu_pipe = &imgu->imgu_pipe[pipe]; ++ r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); ++ if (r) ++ dev_err(&imgu->pci_dev->dev, ++ "failed to stop subdev streaming\n"); ++ + dev_dbg(dev, "IMGU streaming is ready to stop"); + r = imgu_s_stream(imgu, false); + if (!r) +-- +2.44.1 + + +From 5d94cfe88d69350e66c38909a243fcd9f36cb7dd Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH 11/11] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.44.1 + diff --git a/patches/6.9/0013-amd-gpio.patch b/patches/6.9/0013-amd-gpio.patch new file mode 100644 index 0000000000..d81a92dd67 --- /dev/null +++ b/patches/6.9/0013-amd-gpio.patch @@ -0,0 +1,110 @@ +From df9777d27612996bc9fb66392c4501ede5bc0b40 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH 1/2] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 4bf82dbd2a6b..7a8cb090c656 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1216,6 +1217,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1271,6 +1283,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.44.1 + + +From 8952d7102223ba7b0509b0883fdd136ad1b4d51a Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH 2/2] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 + override quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 7a8cb090c656..0faafc323e67 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1219,12 +1219,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.44.1 + diff --git a/patches/6.9/0014-rtc.patch b/patches/6.9/0014-rtc.patch new file mode 100644 index 0000000000..71589a72af --- /dev/null +++ b/patches/6.9/0014-rtc.patch @@ -0,0 +1,110 @@ +From a3e68b456c60e19282771143c322f05fb85a6fb7 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 1d670dbe4d1d..71c9e375ca1c 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -432,6 +432,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -480,15 +488,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -564,13 +571,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -612,12 +624,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -648,6 +654,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.44.1 + From d7da4a837265f38178524fbf319275313db70cd8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 21:38:00 +0200 Subject: [PATCH 013/236] Update v6.9 patches Changes: - Add SAM support for Surface Laptop 6 - Rework fix for SAM probing Links: - kernel: https://github.com/linux-surface/kernel/commit/3d121f2b6dce2eb9c972749225699a1f2079b5de --- patches/6.9/0001-secureboot.patch | 37 ++ ...e3-oemb.patch => 0002-surface3-oemb.patch} | 10 +- ...{0002-mwifiex.patch => 0003-mwifiex.patch} | 36 +- .../{0003-ath10k.patch => 0004-ath10k.patch} | 6 +- .../6.9/{0004-ipts.patch => 0005-ipts.patch} | 97 ++-- .../6.9/{0005-ithc.patch => 0006-ithc.patch} | 91 ++-- ...rface-sam.patch => 0007-surface-sam.patch} | 466 ++++++++++++++---- ....patch => 0008-surface-sam-over-hid.patch} | 22 +- ...button.patch => 0009-surface-button.patch} | 40 +- ...ver.patch => 0010-surface-typecover.patch} | 30 +- ...down.patch => 0011-surface-shutdown.patch} | 10 +- ...rface-gpe.patch => 0012-surface-gpe.patch} | 6 +- ...{0012-cameras.patch => 0013-cameras.patch} | 112 ++--- ...013-amd-gpio.patch => 0014-amd-gpio.patch} | 19 +- .../6.9/{0014-rtc.patch => 0015-rtc.patch} | 6 +- 15 files changed, 635 insertions(+), 353 deletions(-) create mode 100644 patches/6.9/0001-secureboot.patch rename patches/6.9/{0001-surface3-oemb.patch => 0002-surface3-oemb.patch} (94%) rename patches/6.9/{0002-mwifiex.patch => 0003-mwifiex.patch} (95%) rename patches/6.9/{0003-ath10k.patch => 0004-ath10k.patch} (97%) rename patches/6.9/{0004-ipts.patch => 0005-ipts.patch} (97%) rename patches/6.9/{0005-ithc.patch => 0006-ithc.patch} (99%) rename patches/6.9/{0006-surface-sam.patch => 0007-surface-sam.patch} (72%) rename patches/6.9/{0007-surface-sam-over-hid.patch => 0008-surface-sam-over-hid.patch} (95%) rename patches/6.9/{0008-surface-button.patch => 0009-surface-button.patch} (93%) rename patches/6.9/{0009-surface-typecover.patch => 0010-surface-typecover.patch} (96%) rename patches/6.9/{0010-surface-shutdown.patch => 0011-surface-shutdown.patch} (94%) rename patches/6.9/{0011-surface-gpe.patch => 0012-surface-gpe.patch} (92%) rename patches/6.9/{0012-cameras.patch => 0013-cameras.patch} (91%) rename patches/6.9/{0013-amd-gpio.patch => 0014-amd-gpio.patch} (88%) rename patches/6.9/{0014-rtc.patch => 0015-rtc.patch} (96%) diff --git a/patches/6.9/0001-secureboot.patch b/patches/6.9/0001-secureboot.patch new file mode 100644 index 0000000000..223c1ab2c0 --- /dev/null +++ b/patches/6.9/0001-secureboot.patch @@ -0,0 +1,37 @@ +From 24686c656a230f642f8ed6c09c184660c08cf46c Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359bc..a1bbedd989e42 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.45.1 + diff --git a/patches/6.9/0001-surface3-oemb.patch b/patches/6.9/0002-surface3-oemb.patch similarity index 94% rename from patches/6.9/0001-surface3-oemb.patch rename to patches/6.9/0002-surface3-oemb.patch index 3a83c37c15..211d83cd19 100644 --- a/patches/6.9/0001-surface3-oemb.patch +++ b/patches/6.9/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 77d6e5b59e54e265d824fa4fd8e342cb79ba52e4 Mon Sep 17 00:00:00 2001 +From a494cdb84ee162accff966a0012992e36e4b0c0a Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -40,7 +40,7 @@ Patchset: surface3-oemb 3 files changed, 24 insertions(+) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index c15ed7a12784..1ec8edb5aafa 100644 +index c15ed7a12784a..1ec8edb5aafaf 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { @@ -58,7 +58,7 @@ index c15ed7a12784..1ec8edb5aafa 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index d0d24a53df74..43e06166a5d9 100644 +index d0d24a53df746..43e06166a5d95 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3777,6 +3777,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -78,7 +78,7 @@ index d0d24a53df74..43e06166a5d9 100644 /* * Match for the GPDwin which unfortunately uses somewhat diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index 5e2ec60e2954..207868c699f2 100644 +index 5e2ec60e2954b..207868c699f29 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { @@ -97,5 +97,5 @@ index 5e2ec60e2954..207868c699f2 100644 }; -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0002-mwifiex.patch b/patches/6.9/0003-mwifiex.patch similarity index 95% rename from patches/6.9/0002-mwifiex.patch rename to patches/6.9/0003-mwifiex.patch index 4912f75e9d..ca64439b05 100644 --- a/patches/6.9/0002-mwifiex.patch +++ b/patches/6.9/0003-mwifiex.patch @@ -1,7 +1,7 @@ -From 38ff71a84e7a1ad3de25056f8e5629eb749a85e8 Mon Sep 17 00:00:00 2001 +From 1abf1feb3b521abe9f9c9e8d68d2014e90ecb20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 -Subject: [PATCH 1/3] mwifiex: Add quirk resetting the PCI bridge on MS Surface +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface devices The most recent firmware of the 88W8897 card reports a hardcoded LTR @@ -32,7 +32,7 @@ Patchset: mwifiex 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 5f997becdbaa..9a9929424513 100644 +index 5f997becdbaa2..9a9929424513a 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) @@ -58,7 +58,7 @@ index 5f997becdbaa..9a9929424513 100644 mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 +index dd6d21f1dbfd7..f46b06f8d6435 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -151,7 +151,7 @@ index dd6d21f1dbfd..f46b06f8d643 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 +index d6ff964aec5bf..5d30ae39d65ec 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -4,6 +4,7 @@ @@ -163,13 +163,12 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.44.1 +2.45.1 - -From 47109fad48e842ffedf33bcb07f5080e1350337d Mon Sep 17 00:00:00 2001 +From 0574bff98f5f5af132783f8f72e8ef22e3f36097 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 -Subject: [PATCH 2/3] mwifiex: pcie: disable bridge_d3 for Surface gen4+ +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ Currently, mwifiex fw will crash after suspend on recent kernel series. On Windows, it seems that the root port of wifi will never enter D3 state @@ -188,7 +187,7 @@ Patchset: mwifiex 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 9a9929424513..2273e3029776 100644 +index 9a9929424513a..2273e30297766 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, @@ -213,7 +212,7 @@ index 9a9929424513..2273e3029776 100644 } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 +index f46b06f8d6435..99b024ecbadea 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -307,7 +306,7 @@ index f46b06f8d643..99b024ecbade 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 +index 5d30ae39d65ec..c14eb56eb9118 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -5,6 +5,7 @@ @@ -319,14 +318,13 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.44.1 - +2.45.1 -From 57cd8aeebe2fd4913281c93611277fca158a9c77 Mon Sep 17 00:00:00 2001 +From 8a4ee131ced8068371a8fa09da17d82414e6d835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 -Subject: [PATCH 3/3] Bluetooth: btusb: Lower passive lescan interval on - Marvell 88W8897 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) is used in a lot of Microsoft Surface devices, and all those devices @@ -358,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index fb716849b60f..1e7b3798108f 100644 +index fb716849b60f3..1e7b3798108f7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -398,5 +396,5 @@ index fb716849b60f..1e7b3798108f 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0003-ath10k.patch b/patches/6.9/0004-ath10k.patch similarity index 97% rename from patches/6.9/0003-ath10k.patch rename to patches/6.9/0004-ath10k.patch index a856c01d2d..e8874603ac 100644 --- a/patches/6.9/0003-ath10k.patch +++ b/patches/6.9/0004-ath10k.patch @@ -1,4 +1,4 @@ -From be4b537a27b26a55c4557398ebeead056c446c1b Mon Sep 17 00:00:00 2001 +From fc56de38d725edc7c3856c2a2d369e1f170f202f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 58 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index fa5e2e651831..8921b0ebf36b 100644 +index fa5e2e6518313..8921b0ebf36b7 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -39,6 +39,9 @@ static bool fw_diag_log; @@ -117,5 +117,5 @@ index fa5e2e651831..8921b0ebf36b 100644 ret = firmware_request_nowarn(&fw, filename, ar->dev); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0004-ipts.patch b/patches/6.9/0005-ipts.patch similarity index 97% rename from patches/6.9/0004-ipts.patch rename to patches/6.9/0005-ipts.patch index d01dbb63ed..3b79e84de7 100644 --- a/patches/6.9/0004-ipts.patch +++ b/patches/6.9/0005-ipts.patch @@ -1,7 +1,7 @@ -From 64bf8dc5156002a92eab306a503ae7e89a7ca3be Mon Sep 17 00:00:00 2001 +From ee272e8a81f073b5475a3bb2c3085b55f181bc24 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 -Subject: [PATCH 1/4] mei: me: Add Icelake device ID for iTouch +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch Signed-off-by: Dorian Stoll Patchset: ipts @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index c3a6657dcd4a..82eef2f4eb0a 100644 +index c3a6657dcd4a2..82eef2f4eb0a8 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index c3a6657dcd4a..82eef2f4eb0a 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 7f59dd38c32f..a56ad5b3f779 100644 +index 7f59dd38c32f5..a56ad5b3f7790 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,13 +35,12 @@ index 7f59dd38c32f..a56ad5b3f779 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.44.1 +2.45.1 - -From 8ac49646a71a247ca8ce3348572809866d7d4cd0 Mon Sep 17 00:00:00 2001 +From 8536601cfc6d7671f4c11cab4dca57674f59b349 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 -Subject: [PATCH 2/4] iommu: Use IOMMU passthrough mode for IPTS +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: @@ -62,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index e4a03588a8a0..61bc54299a59 100644 +index e4a03588a8a0f..61bc54299a591 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -143,13 +142,12 @@ index e4a03588a8a0..61bc54299a59 100644 { if (risky_device(dev)) -- -2.44.1 - +2.45.1 -From d7581a727eabc72550a834ae375f20db53da63ee Mon Sep 17 00:00:00 2001 +From 664128ab9984f6c774d4064548d9b247041d2520 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 -Subject: [PATCH 3/4] hid: Add support for Intel Precise Touch and Stylus +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus Based on linux-surface/intel-precise-touch@8abe268 @@ -213,7 +211,7 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 4c682c650704..a263e49b2ae2 100644 +index 4c682c6507040..a263e49b2ae29 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1351,4 +1351,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" @@ -224,7 +222,7 @@ index 4c682c650704..a263e49b2ae2 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 082a728eac60..f4bad1b8d813 100644 +index 082a728eac600..f4bad1b8d813f 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -170,3 +170,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ @@ -235,7 +233,7 @@ index 082a728eac60..f4bad1b8d813 100644 +obj-$(CONFIG_HID_IPTS) += ipts/ diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 000000000000..297401bd388d +index 0000000000000..297401bd388dd --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -255,7 +253,7 @@ index 000000000000..297401bd388d + module will be called ipts. diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile new file mode 100644 -index 000000000000..883896f68e6a +index 0000000000000..883896f68e6ad --- /dev/null +++ b/drivers/hid/ipts/Makefile @@ -0,0 +1,16 @@ @@ -277,7 +275,7 @@ index 000000000000..883896f68e6a +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 000000000000..63a4934bbc5f +index 0000000000000..63a4934bbc5fa --- /dev/null +++ b/drivers/hid/ipts/cmd.c @@ -0,0 +1,61 @@ @@ -344,7 +342,7 @@ index 000000000000..63a4934bbc5f +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 000000000000..2b4079075b64 +index 0000000000000..2b4079075b642 --- /dev/null +++ b/drivers/hid/ipts/cmd.h @@ -0,0 +1,60 @@ @@ -410,7 +408,7 @@ index 000000000000..2b4079075b64 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 000000000000..ba33259f1f7c +index 0000000000000..ba33259f1f7c5 --- /dev/null +++ b/drivers/hid/ipts/context.h @@ -0,0 +1,52 @@ @@ -468,7 +466,7 @@ index 000000000000..ba33259f1f7c +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 000000000000..5360842d260b +index 0000000000000..5360842d260ba --- /dev/null +++ b/drivers/hid/ipts/control.c @@ -0,0 +1,486 @@ @@ -960,7 +958,7 @@ index 000000000000..5360842d260b +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 000000000000..26629c5144ed +index 0000000000000..26629c5144edb --- /dev/null +++ b/drivers/hid/ipts/control.h @@ -0,0 +1,126 @@ @@ -1092,7 +1090,7 @@ index 000000000000..26629c5144ed +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 000000000000..307438c7c80c +index 0000000000000..307438c7c80cd --- /dev/null +++ b/drivers/hid/ipts/desc.h @@ -0,0 +1,80 @@ @@ -1178,7 +1176,7 @@ index 000000000000..307438c7c80c +#endif /* IPTS_DESC_H */ diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 000000000000..ecbb3a8bdaf6 +index 0000000000000..ecbb3a8bdaf60 --- /dev/null +++ b/drivers/hid/ipts/eds1.c @@ -0,0 +1,103 @@ @@ -1287,7 +1285,7 @@ index 000000000000..ecbb3a8bdaf6 +} diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h new file mode 100644 -index 000000000000..eeeb6575e3e8 +index 0000000000000..eeeb6575e3e89 --- /dev/null +++ b/drivers/hid/ipts/eds1.h @@ -0,0 +1,35 @@ @@ -1328,7 +1326,7 @@ index 000000000000..eeeb6575e3e8 + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c new file mode 100644 -index 000000000000..198dc65d7887 +index 0000000000000..198dc65d78876 --- /dev/null +++ b/drivers/hid/ipts/eds2.c @@ -0,0 +1,144 @@ @@ -1478,7 +1476,7 @@ index 000000000000..198dc65d7887 +} diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h new file mode 100644 -index 000000000000..064e3716907a +index 0000000000000..064e3716907ab --- /dev/null +++ b/drivers/hid/ipts/eds2.h @@ -0,0 +1,35 @@ @@ -1519,7 +1517,7 @@ index 000000000000..064e3716907a + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c new file mode 100644 -index 000000000000..e34a1a4f9fa7 +index 0000000000000..e34a1a4f9fa77 --- /dev/null +++ b/drivers/hid/ipts/hid.c @@ -0,0 +1,225 @@ @@ -1750,7 +1748,7 @@ index 000000000000..e34a1a4f9fa7 +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 000000000000..1ebe77447903 +index 0000000000000..1ebe77447903a --- /dev/null +++ b/drivers/hid/ipts/hid.h @@ -0,0 +1,24 @@ @@ -1780,7 +1778,7 @@ index 000000000000..1ebe77447903 +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 000000000000..fb5b5c13ee3e +index 0000000000000..fb5b5c13ee3ea --- /dev/null +++ b/drivers/hid/ipts/main.c @@ -0,0 +1,126 @@ @@ -1912,7 +1910,7 @@ index 000000000000..fb5b5c13ee3e +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 000000000000..1e0395ceae4a +index 0000000000000..1e0395ceae4a4 --- /dev/null +++ b/drivers/hid/ipts/mei.c @@ -0,0 +1,188 @@ @@ -2106,7 +2104,7 @@ index 000000000000..1e0395ceae4a +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 000000000000..973bade6b0fd +index 0000000000000..973bade6b0fdd --- /dev/null +++ b/drivers/hid/ipts/mei.h @@ -0,0 +1,66 @@ @@ -2178,7 +2176,7 @@ index 000000000000..973bade6b0fd +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 000000000000..ef66c3c9db80 +index 0000000000000..ef66c3c9db807 --- /dev/null +++ b/drivers/hid/ipts/receiver.c @@ -0,0 +1,250 @@ @@ -2434,7 +2432,7 @@ index 000000000000..ef66c3c9db80 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 000000000000..3de7da62d40c +index 0000000000000..3de7da62d40c1 --- /dev/null +++ b/drivers/hid/ipts/receiver.h @@ -0,0 +1,16 @@ @@ -2456,7 +2454,7 @@ index 000000000000..3de7da62d40c +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 000000000000..cc14653b2a9f +index 0000000000000..cc14653b2a9f5 --- /dev/null +++ b/drivers/hid/ipts/resources.c @@ -0,0 +1,131 @@ @@ -2593,7 +2591,7 @@ index 000000000000..cc14653b2a9f +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 000000000000..2068e13285f0 +index 0000000000000..2068e13285f0e --- /dev/null +++ b/drivers/hid/ipts/resources.h @@ -0,0 +1,41 @@ @@ -2640,7 +2638,7 @@ index 000000000000..2068e13285f0 +#endif /* IPTS_RESOURCES_H */ diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h new file mode 100644 -index 000000000000..e8dd98895a7e +index 0000000000000..e8dd98895a7ee --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -2746,7 +2744,7 @@ index 000000000000..e8dd98895a7e +#endif /* IPTS_SPEC_DATA_H */ diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h new file mode 100644 -index 000000000000..41845f9d9025 +index 0000000000000..41845f9d90257 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h @@ -0,0 +1,290 @@ @@ -3042,7 +3040,7 @@ index 000000000000..41845f9d9025 +#endif /* IPTS_SPEC_DEVICE_H */ diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h new file mode 100644 -index 000000000000..5a58d4a0a610 +index 0000000000000..5a58d4a0a610f --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h @@ -0,0 +1,34 @@ @@ -3082,7 +3080,7 @@ index 000000000000..5a58d4a0a610 +#endif /* IPTS_SPEC_HID_H */ diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c new file mode 100644 -index 000000000000..355e92bea26f +index 0000000000000..355e92bea26f8 --- /dev/null +++ b/drivers/hid/ipts/thread.c @@ -0,0 +1,84 @@ @@ -3172,7 +3170,7 @@ index 000000000000..355e92bea26f +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 000000000000..1f966b8b32c4 +index 0000000000000..1f966b8b32c45 --- /dev/null +++ b/drivers/hid/ipts/thread.h @@ -0,0 +1,59 @@ @@ -3236,14 +3234,13 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.44.1 - +2.45.1 -From 802ca4119a92827eddcb63610261fb8dbbae4eba Mon Sep 17 00:00:00 2001 +From ee8823ff409dc4507cc2f7c8f8c474735b005938 Mon Sep 17 00:00:00 2001 From: Jasmin Huber Date: Mon, 15 Apr 2024 10:22:55 +0200 -Subject: [PATCH 4/4] Inlude headers to avoid compiler warnings 6.8 kernels - compile with -Wmissing-prototypes. +Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile + with -Wmissing-prototypes. Signed-off-by: Dorian Stoll Patchset: ipts @@ -3254,7 +3251,7 @@ Patchset: ipts 3 files changed, 3 insertions(+) diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c -index ecbb3a8bdaf6..7b9f54388a9f 100644 +index ecbb3a8bdaf60..7b9f54388a9f6 100644 --- a/drivers/hid/ipts/eds1.c +++ b/drivers/hid/ipts/eds1.c @@ -14,6 +14,7 @@ @@ -3266,7 +3263,7 @@ index ecbb3a8bdaf6..7b9f54388a9f 100644 int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c -index 198dc65d7887..639940794615 100644 +index 198dc65d78876..639940794615d 100644 --- a/drivers/hid/ipts/eds2.c +++ b/drivers/hid/ipts/eds2.c @@ -15,6 +15,7 @@ @@ -3278,7 +3275,7 @@ index 198dc65d7887..639940794615 100644 int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -index ef66c3c9db80..977724c728c3 100644 +index ef66c3c9db807..977724c728c3e 100644 --- a/drivers/hid/ipts/receiver.c +++ b/drivers/hid/ipts/receiver.c @@ -16,6 +16,7 @@ @@ -3290,5 +3287,5 @@ index ef66c3c9db80..977724c728c3 100644 #include "spec-device.h" #include "thread.h" -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0005-ithc.patch b/patches/6.9/0006-ithc.patch similarity index 99% rename from patches/6.9/0005-ithc.patch rename to patches/6.9/0006-ithc.patch index 0c749a450f..2f9e19ba26 100644 --- a/patches/6.9/0005-ithc.patch +++ b/patches/6.9/0006-ithc.patch @@ -1,7 +1,7 @@ -From c6eae6f4321c2daafedaaf1f81201eed78291c8b Mon Sep 17 00:00:00 2001 +From 4b17942da35790b0e703a87267545f5a9f08e1cf Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 -Subject: [PATCH 1/3] iommu: intel: Disable source id verification for ITHC +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC Signed-off-by: Dorian Stoll Patchset: ithc @@ -10,7 +10,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 566297bc87dd..a8cd8f12d593 100644 +index 566297bc87ddb..a8cd8f12d5937 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -386,6 +386,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) @@ -37,13 +37,12 @@ index 566297bc87dd..a8cd8f12d593 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.44.1 +2.45.1 - -From 9269060ff3088a0d1c33cf7ca134f1db48c99fd6 Mon Sep 17 00:00:00 2001 +From 14baff1c79b6499868b48e6fb4ada851db35c941 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 -Subject: [PATCH 2/3] hid: Add support for Intel Touch Host Controller +Subject: [PATCH] hid: Add support for Intel Touch Host Controller Based on quo/ithc-linux@0b8b45d @@ -73,7 +72,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index a263e49b2ae2..03f0f5af289a 100644 +index a263e49b2ae29..03f0f5af289a4 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1353,4 +1353,6 @@ source "drivers/hid/surface-hid/Kconfig" @@ -84,7 +83,7 @@ index a263e49b2ae2..03f0f5af289a 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index f4bad1b8d813..d32c194400ae 100644 +index f4bad1b8d813f..d32c194400aea 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -94,7 +93,7 @@ index f4bad1b8d813..d32c194400ae 100644 +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 000000000000..aea83f2ac07b +index 0000000000000..aea83f2ac07b4 --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -106,7 +105,7 @@ index 000000000000..aea83f2ac07b + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 000000000000..ede713023609 +index 0000000000000..ede7130236096 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -124,7 +123,7 @@ index 000000000000..ede713023609 + module will be called ithc. diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c new file mode 100644 -index 000000000000..1f1f1e33f2e5 +index 0000000000000..1f1f1e33f2e5a --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,130 @@ @@ -260,7 +259,7 @@ index 000000000000..1f1f1e33f2e5 + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 000000000000..ffb8689b8a78 +index 0000000000000..ffb8689b8a780 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,373 @@ @@ -639,7 +638,7 @@ index 000000000000..ffb8689b8a78 + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 000000000000..93652e4476bf +index 0000000000000..93652e4476bf8 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,69 @@ @@ -714,7 +713,7 @@ index 000000000000..93652e4476bf + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000000..87ed4aa70fda +index 0000000000000..87ed4aa70fda0 --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,728 @@ @@ -1448,7 +1447,7 @@ index 000000000000..87ed4aa70fda + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 000000000000..e058721886e3 +index 0000000000000..e058721886e37 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,96 @@ @@ -1550,7 +1549,7 @@ index 000000000000..e058721886e3 + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 000000000000..d4007d9e2bac +index 0000000000000..d4007d9e2bacc --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,189 @@ @@ -1745,7 +1744,7 @@ index 000000000000..d4007d9e2bac + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 000000000000..028e55a4ec53 +index 0000000000000..028e55a4ec53e --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,67 @@ @@ -1817,13 +1816,12 @@ index 000000000000..028e55a4ec53 +void ithc_log_regs(struct ithc *ithc); + -- -2.44.1 - +2.45.1 -From b6f9694876ec4a59690a80e4ee6affcc740cca9a Mon Sep 17 00:00:00 2001 +From 2537922b2f0c1d0002a2afe6d0fc79695add8e60 Mon Sep 17 00:00:00 2001 From: quo Date: Fri, 19 Apr 2024 22:11:09 +0200 -Subject: [PATCH 3/3] hid: ithc: Update from quo/ithc-linux +Subject: [PATCH] hid: ithc: Update from quo/ithc-linux - Added QuickSPI support for Surface Laptop Studio 2 - Use Latency Tolerance Reporting instead of manual CPU latency adjustments @@ -1842,13 +1840,13 @@ Patchset: ithc drivers/hid/ithc/ithc-hid.h | 32 ++ drivers/hid/ithc/ithc-legacy.c | 252 ++++++++++++++ drivers/hid/ithc/ithc-legacy.h | 8 + - drivers/hid/ithc/ithc-main.c | 384 ++++---------------- + drivers/hid/ithc/ithc-main.c | 386 ++++----------------- drivers/hid/ithc/ithc-quickspi.c | 578 +++++++++++++++++++++++++++++++ drivers/hid/ithc/ithc-quickspi.h | 39 +++ drivers/hid/ithc/ithc-regs.c | 72 +++- drivers/hid/ithc/ithc-regs.h | 143 ++++---- drivers/hid/ithc/ithc.h | 71 ++-- - 15 files changed, 1440 insertions(+), 537 deletions(-) + 15 files changed, 1441 insertions(+), 538 deletions(-) create mode 100644 drivers/hid/ithc/ithc-debug.h create mode 100644 drivers/hid/ithc/ithc-hid.c create mode 100644 drivers/hid/ithc/ithc-hid.h @@ -1858,7 +1856,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc-quickspi.h diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild -index aea83f2ac07b..4937ba131297 100644 +index aea83f2ac07b4..4937ba1312973 100644 --- a/drivers/hid/ithc/Kbuild +++ b/drivers/hid/ithc/Kbuild @@ -1,6 +1,6 @@ @@ -1870,7 +1868,7 @@ index aea83f2ac07b..4937ba131297 100644 ccflags-y := -std=gnu11 -Wno-declaration-after-statement diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c -index 1f1f1e33f2e5..2d8c6afe9966 100644 +index 1f1f1e33f2e5a..2d8c6afe99663 100644 --- a/drivers/hid/ithc/ithc-debug.c +++ b/drivers/hid/ithc/ithc-debug.c @@ -85,10 +85,11 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si @@ -1937,7 +1935,7 @@ index 1f1f1e33f2e5..2d8c6afe9966 100644 *dbgm = dbg; diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h new file mode 100644 -index 000000000000..38c53d916bdb +index 0000000000000..38c53d916bdb5 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.h @@ -0,0 +1,7 @@ @@ -1949,7 +1947,7 @@ index 000000000000..38c53d916bdb +void ithc_log_regs(struct ithc *ithc); + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c -index ffb8689b8a78..bf4eab33062b 100644 +index ffb8689b8a780..bf4eab33062b0 100644 --- a/drivers/hid/ithc/ithc-dma.c +++ b/drivers/hid/ithc/ithc-dma.c @@ -173,10 +173,9 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel) @@ -2130,7 +2128,7 @@ index ffb8689b8a78..bf4eab33062b 100644 return ret; } diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h -index 93652e4476bf..1749a5819b3e 100644 +index 93652e4476bf8..1749a5819b3e7 100644 --- a/drivers/hid/ithc/ithc-dma.h +++ b/drivers/hid/ithc/ithc-dma.h @@ -11,27 +11,6 @@ struct ithc_phys_region_desc { @@ -2178,7 +2176,7 @@ index 93652e4476bf..1749a5819b3e 100644 diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c new file mode 100644 -index 000000000000..065646ab499e +index 0000000000000..065646ab499ef --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.c @@ -0,0 +1,207 @@ @@ -2391,7 +2389,7 @@ index 000000000000..065646ab499e + diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h new file mode 100644 -index 000000000000..599eb912c8c8 +index 0000000000000..599eb912c8c84 --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.h @@ -0,0 +1,32 @@ @@ -2429,7 +2427,7 @@ index 000000000000..599eb912c8c8 + diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c new file mode 100644 -index 000000000000..5c1da11e3f1d +index 0000000000000..5c1da11e3f1d2 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.c @@ -0,0 +1,252 @@ @@ -2687,7 +2685,7 @@ index 000000000000..5c1da11e3f1d + diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h new file mode 100644 -index 000000000000..28d692462072 +index 0000000000000..28d6924620722 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.h @@ -0,0 +1,8 @@ @@ -2700,7 +2698,7 @@ index 000000000000..28d692462072 + size_t maxlen); + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -index 87ed4aa70fda..2acf02e41d40 100644 +index 87ed4aa70fda0..2acf02e41d40f 100644 --- a/drivers/hid/ithc/ithc-main.c +++ b/drivers/hid/ithc/ithc-main.c @@ -5,28 +5,6 @@ @@ -3130,15 +3128,16 @@ index 87ed4aa70fda..2acf02e41d40 100644 + : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 + : 100 * 1000 * 1000; + ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); - -- // Waiting for the following status bit makes reading config much more reliable, -- // however the official driver does not seem to do this... -- CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4); ++ + if (ithc->use_quickspi) + CHECK_RET(ithc_quickspi_init, ithc, &cfg); + else + CHECK_RET(ithc_legacy_init, ithc); +- // Waiting for the following status bit makes reading config much more reliable, +- // however the official driver does not seem to do this... +- CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4); +- - // Read configuration data. - for (int retries = 0; ; retries++) { - ithc_log_regs(ithc); @@ -3230,10 +3229,10 @@ index 87ed4aa70fda..2acf02e41d40 100644 // because it calls ithc_hid_parse() which reads the report descriptor via DMA. - CHECK_RET(hid_add_device, ithc->hid); + CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); - CHECK(ithc_debug_init, ithc); -+ CHECK(ithc_debug_init_device, ithc); -+ + ithc_set_ltr_idle(ithc); pci_dbg(pci, "started\n"); @@ -3261,7 +3260,7 @@ index 87ed4aa70fda..2acf02e41d40 100644 module_init(ithc_init); diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c new file mode 100644 -index 000000000000..760e55ead078 +index 0000000000000..760e55ead0788 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.c @@ -0,0 +1,578 @@ @@ -3845,7 +3844,7 @@ index 000000000000..760e55ead078 + diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h new file mode 100644 -index 000000000000..74d882f6b2f0 +index 0000000000000..74d882f6b2f0a --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.h @@ -0,0 +1,39 @@ @@ -3889,7 +3888,7 @@ index 000000000000..74d882f6b2f0 + size_t maxlen); + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c -index e058721886e3..c0f13506af20 100644 +index e058721886e37..c0f13506af205 100644 --- a/drivers/hid/ithc/ithc-regs.c +++ b/drivers/hid/ithc/ithc-regs.c @@ -22,46 +22,104 @@ void bitsb(__iomem u8 *reg, u8 mask, u8 val) @@ -4005,7 +4004,7 @@ index e058721886e3..c0f13506af20 100644 return -EINVAL; diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h -index d4007d9e2bac..a9d236454644 100644 +index d4007d9e2bacc..a9d2364546442 100644 --- a/drivers/hid/ithc/ithc-regs.h +++ b/drivers/hid/ithc/ithc-regs.h @@ -1,14 +1,34 @@ @@ -4226,7 +4225,7 @@ index d4007d9e2bac..a9d236454644 100644 int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h -index 028e55a4ec53..e90c38044432 100644 +index 028e55a4ec53e..e90c380444325 100644 --- a/drivers/hid/ithc/ithc.h +++ b/drivers/hid/ithc/ithc.h @@ -1,20 +1,19 @@ @@ -4337,5 +4336,5 @@ index 028e55a4ec53..e90c38044432 100644 -void ithc_log_regs(struct ithc *ithc); -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0006-surface-sam.patch b/patches/6.9/0007-surface-sam.patch similarity index 72% rename from patches/6.9/0006-surface-sam.patch rename to patches/6.9/0007-surface-sam.patch index 01a3e1b153..a3f41abd1c 100644 --- a/patches/6.9/0006-surface-sam.patch +++ b/patches/6.9/0007-surface-sam.patch @@ -1,7 +1,279 @@ -From 9740f9a56b1dff713a6bde51386ceece9bf9b37a Mon Sep 17 00:00:00 2001 +From b4563a0da733d5759de36d9e555ce81324dca286 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 9 May 2024 16:15:49 +0200 +Subject: [PATCH] serial: Clear UPF_DEAD before calling + tty_port_register_device_attr_serdev() + +If a serdev_device_driver is already loaded for a serdev_tty_port when it +gets registered by tty_port_register_device_attr_serdev() then that +driver's probe() method will be called immediately. + +The serdev_device_driver's probe() method should then be able to call +serdev_device_open() successfully, but because UPF_DEAD is still dead +serdev_device_open() will fail with -ENXIO in this scenario: + + serdev_device_open() + ctrl->ops->open() /* this callback being ttyport_open() */ + tty->ops->open() /* this callback being uart_open() */ + tty_port_open() + port->ops->activate() /* this callback being uart_port_activate() */ + Find bit UPF_DEAD is set in uport->flags and fail with errno -ENXIO. + +Fix this be clearing UPF_DEAD before tty_port_register_device_attr_serdev() +note this only moves up the UPD_DEAD clearing a small bit, before: + + tty_port_register_device_attr_serdev(); + mutex_unlock(&tty_port.mutex); + uart_port.flags &= ~UPF_DEAD; + mutex_unlock(&port_mutex); + +after: + + uart_port.flags &= ~UPF_DEAD; + tty_port_register_device_attr_serdev(); + mutex_unlock(&tty_port.mutex); + mutex_unlock(&port_mutex); + +Reported-by: Weifeng Liu +Closes: https://lore.kernel.org/platform-driver-x86/20240505130800.2546640-1-weifeng.liu.z@gmail.com/ +Tested-by: Weifeng Liu +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20240509141549.63704-1-hdegoede@redhat.com +Signed-off-by: Greg Kroah-Hartman +Patchset: surface-sam +--- + drivers/tty/serial/serial_core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c +index c476d884356db..b47a277978a0b 100644 +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -3211,6 +3211,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u + if (uport->attr_group) + uport->tty_groups[1] = uport->attr_group; + ++ /* Ensure serdev drivers can call serdev_device_open() right away */ ++ uport->flags &= ~UPF_DEAD; ++ + /* + * Register the port whether it's detected or not. This allows + * setserial to be used to alter this port's parameters. +@@ -3221,6 +3224,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u + if (!IS_ERR(tty_dev)) { + device_set_wakeup_capable(tty_dev, 1); + } else { ++ uport->flags |= UPF_DEAD; + dev_err(uport->dev, "Cannot register tty device on line %d\n", + uport->line); + } +@@ -3426,8 +3430,6 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) + if (ret) + goto err_unregister_port_dev; + +- port->flags &= ~UPF_DEAD; +- + mutex_unlock(&port_mutex); + + return 0; +-- +2.45.1 + +From 0864ded554efe90dd9603b61e82c604481ee5125 Mon Sep 17 00:00:00 2001 +From: Weifeng Liu +Date: Sun, 5 May 2024 21:07:50 +0800 +Subject: [PATCH] platform/surface: aggregator: Log critical errors during SAM + probing + +Emits messages upon errors during probing of SAM. Hopefully this could +provide useful context to user for the purpose of diagnosis when +something miserable happen. + +Reviewed-by: Maximilian Luz +Reviewed-by: Andy Shevchenko +Signed-off-by: Weifeng Liu +Link: https://lore.kernel.org/r/20240505130800.2546640-3-weifeng.liu.z@gmail.com +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +Patchset: surface-sam +--- + drivers/platform/surface/aggregator/core.c | 42 ++++++++++++++-------- + 1 file changed, 28 insertions(+), 14 deletions(-) + +diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c +index ba550eaa06fcf..797d0645bd77f 100644 +--- a/drivers/platform/surface/aggregator/core.c ++++ b/drivers/platform/surface/aggregator/core.c +@@ -618,15 +618,17 @@ static const struct acpi_gpio_mapping ssam_acpi_gpios[] = { + + static int ssam_serial_hub_probe(struct serdev_device *serdev) + { +- struct acpi_device *ssh = ACPI_COMPANION(&serdev->dev); ++ struct device *dev = &serdev->dev; ++ struct acpi_device *ssh = ACPI_COMPANION(dev); + struct ssam_controller *ctrl; + acpi_status astatus; + int status; + +- if (gpiod_count(&serdev->dev, NULL) < 0) +- return -ENODEV; ++ status = gpiod_count(dev, NULL); ++ if (status < 0) ++ return dev_err_probe(dev, status, "no GPIO found\n"); + +- status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios); ++ status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios); + if (status) + return status; + +@@ -637,8 +639,10 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + + /* Initialize controller. */ + status = ssam_controller_init(ctrl, serdev); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "failed to initialize ssam controller\n"); + goto err_ctrl_init; ++ } + + ssam_controller_lock(ctrl); + +@@ -646,12 +650,14 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + serdev_device_set_drvdata(serdev, ctrl); + serdev_device_set_client_ops(serdev, &ssam_serdev_ops); + status = serdev_device_open(serdev); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "failed to open serdev device\n"); + goto err_devopen; ++ } + + astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev); + if (ACPI_FAILURE(astatus)) { +- status = -ENXIO; ++ status = dev_err_probe(dev, -ENXIO, "failed to setup serdev\n"); + goto err_devinit; + } + +@@ -667,25 +673,33 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + * states. + */ + status = ssam_log_firmware_version(ctrl); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "failed to get firmware version\n"); + goto err_initrq; ++ } + + status = ssam_ctrl_notif_d0_entry(ctrl); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "D0-entry notification failed\n"); + goto err_initrq; ++ } + + status = ssam_ctrl_notif_display_on(ctrl); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "display-on notification failed\n"); + goto err_initrq; ++ } + +- status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group); ++ status = sysfs_create_group(&dev->kobj, &ssam_sam_group); + if (status) + goto err_initrq; + + /* Set up IRQ. */ + status = ssam_irq_setup(ctrl); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "failed to setup IRQ\n"); + goto err_irq; ++ } + + /* Finally, set main controller reference. */ + status = ssam_try_set_controller(ctrl); +@@ -702,7 +716,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + * resumed. In short, this causes some spurious unwanted wake-ups. + * For now let's thus default power/wakeup to false. + */ +- device_set_wakeup_capable(&serdev->dev, true); ++ device_set_wakeup_capable(dev, true); + acpi_dev_clear_dependencies(ssh); + + return 0; +@@ -710,7 +724,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + err_mainref: + ssam_irq_free(ctrl); + err_irq: +- sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group); ++ sysfs_remove_group(&dev->kobj, &ssam_sam_group); + err_initrq: + ssam_controller_lock(ctrl); + ssam_controller_shutdown(ctrl); +-- +2.45.1 + +From d44985653441ba783a830bd5efde2fcf3a3ea271 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 19 Apr 2024 20:41:47 +0200 +Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is + destroyed in probe + +There is a small window in ssam_serial_hub_probe() where the controller +is initialized but has not been started yet. Specifically, between +ssam_controller_init() and ssam_controller_start(). Any failure in this +window, for example caused by a failure of serdev_device_open(), +currently results in an incorrect warning being emitted. + +In particular, any failure in this window results in the controller +being destroyed via ssam_controller_destroy(). This function checks the +state of the controller and, in an attempt to validate that the +controller has been cleanly shut down before we try and deallocate any +resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. + +However, since we have only just initialized the controller and have not +yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this +is the only point at which the controller has this state, as it will +change after we start the controller with ssam_controller_start() and +never revert back. Further, at this point no communication has taken +place and the sender and receiver threads have not been started yet (and +we may not even have an open serdev device either). + +Therefore, it is perfectly safe to call ssam_controller_destroy() with a +state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the +warning currently being emitted is incorrect. Fix it by extending the +check. + +Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/platform/surface/aggregator/controller.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c +index 7fc602e01487d..7e89f547999b2 100644 +--- a/drivers/platform/surface/aggregator/controller.c ++++ b/drivers/platform/surface/aggregator/controller.c +@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) + if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) + return; + +- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); ++ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && ++ ctrl->state != SSAM_CONTROLLER_INITIALIZED); + + /* + * Note: New events could still have been received after the previous +-- +2.45.1 + +From 6b6f860bbef0ba3f10f8dc151ac4e27d0a34c223 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Oct 2023 14:57:11 +0200 -Subject: [PATCH 1/7] platform/surface: aggregator_registry: Add support for +Subject: [PATCH] platform/surface: aggregator_registry: Add support for Surface Laptop Go 3 Add SAM client device nodes for the Surface Laptop Go 3. It seems to use @@ -15,7 +287,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 035d6b4105cd..74688a2ed4b2 100644 +index 035d6b4105cd6..74688a2ed4b2e 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -374,6 +374,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { @@ -29,13 +301,12 @@ index 035d6b4105cd..74688a2ed4b2 100644 { "MSHW0123", (unsigned long)ssam_node_group_sls }, -- -2.44.1 - +2.45.1 -From 3bd7bc9cf8aa02303245ed2e6a18d86d8bd8ff80 Mon Sep 17 00:00:00 2001 +From 31b312c25822404e52a81de2525da5c7bae12864 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 19:47:00 +0100 -Subject: [PATCH 2/7] platform/surface: aggregator_registry: Add support for +Subject: [PATCH] platform/surface: aggregator_registry: Add support for Surface Laptop Studio 2 Add SAM client device nodes for the Surface Laptop Studio 2 (SLS2). The @@ -50,7 +321,7 @@ Patchset: surface-sam 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 74688a2ed4b2..f02a933160ff 100644 +index 74688a2ed4b2e..f02a933160ff2 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -253,8 +253,8 @@ static const struct software_node *ssam_node_group_sl5[] = { @@ -100,13 +371,69 @@ index 74688a2ed4b2..f02a933160ff 100644 { }, }; -- -2.44.1 +2.45.1 +From 42f6d14bda5e69c2b5a8d27cfcbd063a5922f876 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 20:05:57 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add support for + Surface Laptop 6 + +Add SAM client device nodes for the Surface Laptop Studio 6 (SL6). The +SL6 is similar to the SL5, with the typical battery/AC, platform +profile, and HID nodes. It also has support for the newly supported fan +interface. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + .../surface/surface_aggregator_registry.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) -From 04d066bc571f06c406ee0837e3db5dfedbba7859 Mon Sep 17 00:00:00 2001 +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index f02a933160ff2..34df1bdad83bd 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -253,6 +253,22 @@ static const struct software_node *ssam_node_group_sl5[] = { + NULL, + }; + ++/* Devices for Surface Laptop 6. */ ++static const struct software_node *ssam_node_group_sl6[] = { ++ &ssam_node_root, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, ++ &ssam_node_hid_main_keyboard, ++ &ssam_node_hid_main_touchpad, ++ &ssam_node_hid_main_iid5, ++ &ssam_node_hid_sam_sensors, ++ &ssam_node_hid_sam_ucm_ucsi, ++ NULL, ++}; ++ + /* Devices for Surface Laptop Studio 1. */ + static const struct software_node *ssam_node_group_sls1[] = { + &ssam_node_root, +@@ -382,6 +398,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Laptop 5 */ + { "MSHW0350", (unsigned long)ssam_node_group_sl5 }, + ++ /* Surface Laptop 6 */ ++ { "MSHW0530", (unsigned long)ssam_node_group_sl5 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.45.1 + +From 88fda328aea3bb7077cd39f854148276dcffcea3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 -Subject: [PATCH 3/7] hwmon: Add thermal sensor driver for Surface Aggregator +Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator Module Some of the newer Microsoft Surface devices (such as the Surface Book @@ -125,7 +452,7 @@ Patchset: surface-sam create mode 100644 drivers/hwmon/surface_temp.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 83945397b6eb..338ef73c96a3 100644 +index 83945397b6eb1..338ef73c96a3a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2070,6 +2070,16 @@ config SENSORS_SURFACE_FAN @@ -146,7 +473,7 @@ index 83945397b6eb..338ef73c96a3 100644 tristate "Texas Instruments ADC128D818" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 5c31808f6378..de8bc99719e6 100644 +index 5c31808f6378d..de8bc99719e63 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -208,6 +208,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o @@ -159,7 +486,7 @@ index 5c31808f6378..de8bc99719e6 100644 obj-$(CONFIG_SENSORS_TC74) += tc74.o diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c new file mode 100644 -index 000000000000..48c3e826713f +index 0000000000000..48c3e826713f6 --- /dev/null +++ b/drivers/hwmon/surface_temp.c @@ -0,0 +1,165 @@ @@ -329,13 +656,12 @@ index 000000000000..48c3e826713f +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.44.1 - +2.45.1 -From f97fa8fb9a6a94abd17c9fbc3fa3c719e6012ca8 Mon Sep 17 00:00:00 2001 +From 17f0ec6ef1bc95e152af3a9f2b05ea669c75d24a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 -Subject: [PATCH 4/7] hwmon: surface_temp: Add support for sensor names +Subject: [PATCH] hwmon: surface_temp: Add support for sensor names The thermal subsystem of the Surface Aggregator Module allows us to query the names of the respective thermal sensors. Forward those to @@ -350,7 +676,7 @@ Patchset: surface-sam 1 file changed, 96 insertions(+), 17 deletions(-) diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c -index 48c3e826713f..4c08926139db 100644 +index 48c3e826713f6..4c08926139dbf 100644 --- a/drivers/hwmon/surface_temp.c +++ b/drivers/hwmon/surface_temp.c @@ -17,6 +17,27 @@ @@ -525,13 +851,12 @@ index 48c3e826713f..4c08926139db 100644 "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, NULL); -- -2.44.1 - +2.45.1 -From 680b16d7ac234ebc3885a898d69105cc00da1c49 Mon Sep 17 00:00:00 2001 +From 54bfa02fe865b9f22d79b112a5244ce81e4961f1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:21:12 +0100 -Subject: [PATCH 5/7] platform/surface: aggregator_registry: Add support for +Subject: [PATCH] platform/surface: aggregator_registry: Add support for thermal sensors on the Surface Pro 9 The Surface Pro 9 has thermal sensors connected via the Surface @@ -544,7 +869,7 @@ Patchset: surface-sam 1 file changed, 7 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index f02a933160ff..67686042e009 100644 +index 34df1bdad83bd..c0bf0cadcd258 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = { @@ -560,7 +885,7 @@ index f02a933160ff..67686042e009 100644 /* Fan speed function. */ static const struct software_node ssam_node_fan_speed = { .name = "ssam:01:05:01:01:01", -@@ -325,6 +331,7 @@ static const struct software_node *ssam_node_group_sp9[] = { +@@ -341,6 +347,7 @@ static const struct software_node *ssam_node_group_sp9[] = { &ssam_node_bat_ac, &ssam_node_bat_main, &ssam_node_tmp_pprof, @@ -569,14 +894,12 @@ index f02a933160ff..67686042e009 100644 &ssam_node_pos_tablet_switch, &ssam_node_hid_kip_keyboard, -- -2.44.1 +2.45.1 - -From 500f45035aa04b231d9b7406a0e6f9ade8d6afb0 Mon Sep 17 00:00:00 2001 +From 06c4b5ac6b6357227e45c53643729140d794b48d Mon Sep 17 00:00:00 2001 From: Ivor Wanders Date: Sat, 16 Dec 2023 15:56:39 -0500 -Subject: [PATCH 6/7] platform/surface: platform_profile: add fan profile - switching +Subject: [PATCH] platform/surface: platform_profile: add fan profile switching Change naming from tmp to platform profile to clarify the module may interact with both the TMP and FAN subystems. Add functionality that @@ -590,7 +913,7 @@ Patchset: surface-sam 2 files changed, 100 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 67686042e009..058b6654a91a 100644 +index c0bf0cadcd258..07a4c4e1120d3 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -68,8 +68,8 @@ static const struct software_node ssam_node_bat_sb3base = { @@ -661,7 +984,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_hid_main_keyboard, &ssam_node_hid_main_touchpad, &ssam_node_hid_main_iid5, -@@ -264,7 +278,7 @@ static const struct software_node *ssam_node_group_sls1[] = { +@@ -280,7 +294,7 @@ static const struct software_node *ssam_node_group_sls1[] = { &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -670,7 +993,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_pos_tablet_switch, &ssam_node_hid_sam_keyboard, &ssam_node_hid_sam_penstash, -@@ -280,7 +294,7 @@ static const struct software_node *ssam_node_group_sls2[] = { +@@ -296,7 +310,7 @@ static const struct software_node *ssam_node_group_sls2[] = { &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -679,7 +1002,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_pos_tablet_switch, &ssam_node_hid_sam_keyboard, &ssam_node_hid_sam_penstash, -@@ -294,7 +308,7 @@ static const struct software_node *ssam_node_group_slg1[] = { +@@ -310,7 +324,7 @@ static const struct software_node *ssam_node_group_slg1[] = { &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -688,7 +1011,7 @@ index 67686042e009..058b6654a91a 100644 NULL, }; -@@ -303,7 +317,7 @@ static const struct software_node *ssam_node_group_sp7[] = { +@@ -319,7 +333,7 @@ static const struct software_node *ssam_node_group_sp7[] = { &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -697,7 +1020,7 @@ index 67686042e009..058b6654a91a 100644 NULL, }; -@@ -313,7 +327,7 @@ static const struct software_node *ssam_node_group_sp8[] = { +@@ -329,7 +343,7 @@ static const struct software_node *ssam_node_group_sp8[] = { &ssam_node_hub_kip, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -706,7 +1029,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_kip_tablet_switch, &ssam_node_hid_kip_keyboard, &ssam_node_hid_kip_penstash, -@@ -330,7 +344,7 @@ static const struct software_node *ssam_node_group_sp9[] = { +@@ -346,7 +360,7 @@ static const struct software_node *ssam_node_group_sp9[] = { &ssam_node_hub_kip, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -716,7 +1039,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_fan_speed, &ssam_node_pos_tablet_switch, diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c -index a5a3941b3f43..e54d0a8f7daa 100644 +index a5a3941b3f43a..e54d0a8f7daa5 100644 --- a/drivers/platform/surface/surface_platform_profile.c +++ b/drivers/platform/surface/surface_platform_profile.c @@ -1,7 +1,7 @@ @@ -860,17 +1183,17 @@ index a5a3941b3f43..e54d0a8f7daa 100644 - tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); + tpd = container_of(pprof, struct ssam_platform_profile_device, handler); ++ ++ tp = convert_profile_to_ssam_tmp(tpd->sdev, profile); ++ if (tp < 0) ++ return tp; - tp = convert_profile_to_ssam(tpd->sdev, profile); -+ tp = convert_profile_to_ssam_tmp(tpd->sdev, profile); ++ tp = ssam_tmp_profile_set(tpd->sdev, tp); if (tp < 0) return tp; - return ssam_tmp_profile_set(tpd->sdev, tp); -+ tp = ssam_tmp_profile_set(tpd->sdev, tp); -+ if (tp < 0) -+ return tp; -+ + if (tpd->has_fan) { + tp = convert_profile_to_ssam_fan(tpd->sdev, profile); + if (tp < 0) @@ -898,60 +1221,5 @@ index a5a3941b3f43..e54d0a8f7daa 100644 set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices); set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices); -- -2.44.1 - - -From 0826fa5b802cae18967e733b525ea175cace518d Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Fri, 19 Apr 2024 20:41:47 +0200 -Subject: [PATCH 7/7] platform/surface: aggregator: Fix warning when controller - is destroyed in probe - -There is a small window in ssam_serial_hub_probe() where the controller -is initialized but has not been started yet. Specifically, between -ssam_controller_init() and ssam_controller_start(). Any failure in this -window, for example caused by a failure of serdev_device_open(), -currently results in an incorrect warning being emitted. - -In particular, any failure in this window results in the controller -being destroyed via ssam_controller_destroy(). This function checks the -state of the controller and, in an attempt to validate that the -controller has been cleanly shut down before we try and deallocate any -resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. - -However, since we have only just initialized the controller and have not -yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this -is the only point at which the controller has this state, as it will -change after we start the controller with ssam_controller_start() and -never revert back. Further, at this point no communication has taken -place and the sender and receiver threads have not been started yet (and -we may not even have an open serdev device either). - -Therefore, it is perfectly safe to call ssam_controller_destroy() with a -state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the -warning currently being emitted is incorrect. Fix it by extending the -check. - -Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") -Signed-off-by: Maximilian Luz ---- - drivers/platform/surface/aggregator/controller.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c -index 7fc602e01487..7e89f547999b 100644 ---- a/drivers/platform/surface/aggregator/controller.c -+++ b/drivers/platform/surface/aggregator/controller.c -@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) - if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) - return; - -- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); -+ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && -+ ctrl->state != SSAM_CONTROLLER_INITIALIZED); - - /* - * Note: New events could still have been received after the previous --- -2.44.1 +2.45.1 diff --git a/patches/6.9/0007-surface-sam-over-hid.patch b/patches/6.9/0008-surface-sam-over-hid.patch similarity index 95% rename from patches/6.9/0007-surface-sam-over-hid.patch rename to patches/6.9/0008-surface-sam-over-hid.patch index 7b76987d92..49133c160a 100644 --- a/patches/6.9/0007-surface-sam-over-hid.patch +++ b/patches/6.9/0008-surface-sam-over-hid.patch @@ -1,7 +1,7 @@ -From 8586d7576a7338e5811b3eb86bfac1bf7b434e06 Mon Sep 17 00:00:00 2001 +From bf55987e82f9ae913b51a6a269fc1a397930f049 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 -Subject: [PATCH 1/2] i2c: acpi: Implement RawBytes read access +Subject: [PATCH] i2c: acpi: Implement RawBytes read access Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C device via a generic serial bus operation region and RawBytes read @@ -55,7 +55,7 @@ Patchset: surface-sam-over-hid 1 file changed, 35 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index d6037a328669..a290ebc77aea 100644 +index d6037a3286690..a290ebc77aea2 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -628,6 +628,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, @@ -108,14 +108,12 @@ index d6037a328669..a290ebc77aea 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.44.1 +2.45.1 - -From c9ed90b27e8847666c754779ba2cbcd11a53efc6 Mon Sep 17 00:00:00 2001 +From ebfda7ad73dd90971be10e9d6f59c51c781accbb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 -Subject: [PATCH 2/2] platform/surface: Add driver for Surface Book 1 dGPU - switch +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch Add driver exposing the discrete GPU power-switch of the Microsoft Surface Book 1 to user-space. @@ -135,7 +133,7 @@ Patchset: surface-sam-over-hid create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index b629e82af97c..68656e8f309e 100644 +index b629e82af97c0..68656e8f309ed 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH @@ -153,7 +151,7 @@ index b629e82af97c..68656e8f309e 100644 tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 +index 53344330939bf..7efcd0cdb5329 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o @@ -166,7 +164,7 @@ index 53344330939b..7efcd0cdb532 100644 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 000000000000..8b816ed8f35c +index 0000000000000..8b816ed8f35c6 --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c @@ -0,0 +1,162 @@ @@ -333,5 +331,5 @@ index 000000000000..8b816ed8f35c +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0008-surface-button.patch b/patches/6.9/0009-surface-button.patch similarity index 93% rename from patches/6.9/0008-surface-button.patch rename to patches/6.9/0009-surface-button.patch index bcda2d88da..232b6ba310 100644 --- a/patches/6.9/0008-surface-button.patch +++ b/patches/6.9/0009-surface-button.patch @@ -1,8 +1,7 @@ -From 4d98c340e8182909ec39477fb382e22952f557c0 Mon Sep 17 00:00:00 2001 +From 1e315f586b0b2bc375b96bb538a3be4c0b09d1ea Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 -Subject: [PATCH 1/2] Input: soc_button_array - support AMD variant Surface - devices +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices The power button on the AMD variant of the Surface Laptop uses the same MSHW0040 device ID as the 5th and later generation of Surface @@ -21,7 +20,7 @@ Patchset: surface-button 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index f6d060377d18..b8603f74eb28 100644 +index f6d060377d189..b8603f74eb286 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -41,18 +40,13 @@ index f6d060377d18..b8603f74eb28 100644 acpi_handle handle = ACPI_HANDLE(dev); - union acpi_object *result; - u64 oem_platform_rev = 0; // valid revisions are nonzero -+ bool exists; - +- - // get OEM platform revision - result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, - MSHW0040_DSM_REVISION, - MSHW0040_DSM_GET_OMPR, NULL, - ACPI_TYPE_INTEGER); -+ // check if OEM platform revision DSM call exists -+ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - +- - if (result) { - oem_platform_rev = result->integer.value; - ACPI_FREE(result); @@ -65,22 +59,26 @@ index f6d060377d18..b8603f74eb28 100644 - */ - if (oem_platform_rev == 0) - return -ENODEV; -- ++ bool exists; + - dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); -- ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + - return 0; + return exists ? 0 : -ENODEV; } /* -- -2.44.1 +2.45.1 - -From cf5cec4b4b5d7dfe98710b232c9e1227599ada1a Mon Sep 17 00:00:00 2001 +From ac551644781bce2145c901b16779114b273c4d49 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 -Subject: [PATCH 2/2] platform/surface: surfacepro3_button: don't load on amd +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd variant The AMD variant of the Surface Laptop report 0 for their OEM platform @@ -98,7 +96,7 @@ Patchset: surface-button 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 +index 2755601f979cd..4240c98ca2265 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) @@ -117,7 +115,7 @@ index 2755601f979c..4240c98ca226 100644 acpi_handle handle = dev->handle; - union acpi_object *result; - u64 oem_platform_rev = 0; // valid revisions are nonzero - +- - // get OEM platform revision - result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, - MSHW0040_DSM_REVISION, @@ -137,7 +135,7 @@ index 2755601f979c..4240c98ca226 100644 - } - - dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); -- + - return oem_platform_rev == 0; + // make sure that OEM platform revision DSM call does not exist + return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, @@ -147,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0009-surface-typecover.patch b/patches/6.9/0010-surface-typecover.patch similarity index 96% rename from patches/6.9/0009-surface-typecover.patch rename to patches/6.9/0010-surface-typecover.patch index 1b3dc2248b..1a6441472e 100644 --- a/patches/6.9/0009-surface-typecover.patch +++ b/patches/6.9/0010-surface-typecover.patch @@ -1,7 +1,7 @@ -From ce569f6ee0bb24bfe2efc37a8aadc287aef1c5eb Mon Sep 17 00:00:00 2001 +From dbe49f128699931e317242ba589c1c22a63eed5f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 -Subject: [PATCH 1/3] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 Type-Cover The touchpad on the Type-Cover of the Surface Go 3 is sometimes not @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index b4783574b8e6..360970620589 100644 +index b4783574b8e66..360970620589a 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,14 +37,13 @@ index b4783574b8e6..360970620589 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.44.1 +2.45.1 - -From 6ec5d78cb24e61fe7601c40032bc1a713a87ad42 Mon Sep 17 00:00:00 2001 +From 89a3afeae85bd60a46bc4c2f0b23fb886452f5be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 -Subject: [PATCH 2/3] hid/multitouch: Turn off Type Cover keyboard backlight - when suspending +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending The Type Cover for Microsoft Surface devices supports a special usb control request to disable or enable the built-in keyboard backlight. @@ -76,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 04a014cd2a2f..89c9b00e6371 100644 +index 04a014cd2a2f6..89c9b00e63712 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -271,14 +270,13 @@ index 04a014cd2a2f..89c9b00e6371 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.44.1 - +2.45.1 -From a62411b28850e81c704a44339d15e29049310efb Mon Sep 17 00:00:00 2001 +From 3e3ecb44c93d8259a2a9e97ccfa09eb5b54d1a90 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 -Subject: [PATCH 3/3] hid/multitouch: Add support for surface pro type cover - tablet switch +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch The Surface Pro Type Cover has several non standard HID usages in it's hid report descriptor. @@ -303,7 +301,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 89c9b00e6371..be131488161c 100644 +index 89c9b00e63712..be131488161cd 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -571,5 +569,5 @@ index 89c9b00e6371..be131488161c 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0010-surface-shutdown.patch b/patches/6.9/0011-surface-shutdown.patch similarity index 94% rename from patches/6.9/0010-surface-shutdown.patch rename to patches/6.9/0011-surface-shutdown.patch index 2e1a027b8d..8402a487f0 100644 --- a/patches/6.9/0010-surface-shutdown.patch +++ b/patches/6.9/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 045c80e1a685de8aa6a306600e5715c320ba3de5 Mon Sep 17 00:00:00 2001 +From 9e0b83c9668c3d0e8e5ce9c254697056940a205d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index af2996d0d17f..3ce0fb61257d 100644 +index af2996d0d17ff..3ce0fb61257dc 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,7 +37,7 @@ index af2996d0d17f..3ce0fb61257d 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index eff7f5df08e2..d1cb4ff3ebc5 100644 +index eff7f5df08e27..d1cb4ff3ebc57 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6253,3 +6253,39 @@ static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev) @@ -81,7 +81,7 @@ index eff7f5df08e2..d1cb4ff3ebc5 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 16493426a04f..0eb821624056 100644 +index 16493426a04ff..0eb821624056d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -465,6 +465,7 @@ struct pci_dev { @@ -93,5 +93,5 @@ index 16493426a04f..0eb821624056 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0011-surface-gpe.patch b/patches/6.9/0012-surface-gpe.patch similarity index 92% rename from patches/6.9/0011-surface-gpe.patch rename to patches/6.9/0012-surface-gpe.patch index 3ace4d2c61..b18860eba5 100644 --- a/patches/6.9/0011-surface-gpe.patch +++ b/patches/6.9/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From f5431b805f716b745dd631d8e4919c03ad0a7e76 Mon Sep 17 00:00:00 2001 +From 739ab84095d8ea8ec8fe05447706c6eb2ffa3f35 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -12,7 +12,7 @@ Patchset: surface-gpe 1 file changed, 17 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index 62fd4004db31..103fc4468262 100644 +index 62fd4004db31a..103fc4468262a 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { @@ -47,5 +47,5 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0012-cameras.patch b/patches/6.9/0013-cameras.patch similarity index 91% rename from patches/6.9/0012-cameras.patch rename to patches/6.9/0013-cameras.patch index 6d13cf3cf2..43894c83c7 100644 --- a/patches/6.9/0012-cameras.patch +++ b/patches/6.9/0013-cameras.patch @@ -1,8 +1,8 @@ -From 9bb6322136d802c4a42df455f0bce54e1691a206 Mon Sep 17 00:00:00 2001 +From 44ed44fe421e484bcf2de223d7e8077302635772 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 -Subject: [PATCH 01/11] ACPI: delay enumeration of devices with a _DEP pointing - to an INT3472 device +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device The clk and regulator frameworks expect clk/regulator consumer-devices to have info about the consumed clks/regulators described in the device's @@ -58,7 +58,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index d1464324de95..5d865a34dd9d 100644 +index d1464324de951..5d865a34dd9db 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2181,6 +2181,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, @@ -72,14 +72,12 @@ index d1464324de95..5d865a34dd9d 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.44.1 +2.45.1 - -From e2f50feee091c07295594805eabe9be3b124352c Mon Sep 17 00:00:00 2001 +From d9d5afcea9880a957d6a8d975a122b4f54ec28c2 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 -Subject: [PATCH 02/11] iommu: intel-ipu: use IOMMU passthrough mode for Intel - IPUs +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, The IPU driver allocates its own page table that is not mapped @@ -102,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 61bc54299a59..a61af0f4e9fc 100644 +index 61bc54299a591..a61af0f4e9fce 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -184,13 +182,12 @@ index 61bc54299a59..a61af0f4e9fc 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.44.1 - +2.45.1 -From d2fd30586a30e3d32063ea33d50d33919ce521c7 Mon Sep 17 00:00:00 2001 +From bbf2fb14fae6c6bda12e156ff9d027913ab7860f Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 -Subject: [PATCH 03/11] platform/x86: int3472: Enable I2c daisy chain +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic can be forwarded to a device connected to the PMIC as though it were @@ -204,7 +201,7 @@ Patchset: cameras 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 1e107fd49f82..e3e1696e7f0e 100644 +index 1e107fd49f828..e3e1696e7f0ee 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) @@ -222,13 +219,12 @@ index 1e107fd49f82..e3e1696e7f0e 100644 return 0; -- -2.44.1 - +2.45.1 -From 2d9a4443e87df40907e443e63435ead7a3bfe88f Mon Sep 17 00:00:00 2001 +From bc2732708fc2a71f7fe3808aa84cc6eabbdd1285 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 -Subject: [PATCH 04/11] platform/x86: int3472: Remap reset GPIO for INT347E +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The driver for this sensor expects a single pin named "enable", but on @@ -247,7 +243,7 @@ Patchset: cameras 1 file changed, 14 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 07b302e09340..1d3097bc7e48 100644 +index 07b302e093407..1d3097bc7e487 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 @@ -278,14 +274,12 @@ index 07b302e09340..1d3097bc7e48 100644 agpio, func, polarity); if (ret) -- -2.44.1 +2.45.1 - -From 1aadc03192c2591c7b07470948df39a1792f2f70 Mon Sep 17 00:00:00 2001 +From 0180b848e145642574d2a91175f92050dcec1ec7 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 -Subject: [PATCH 05/11] media: i2c: Clarify that gain is Analogue gain in - OV7251 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 Update the control ID for the gain control in the ov7251 driver to V4L2_CID_ANALOGUE_GAIN. @@ -297,7 +291,7 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf..9c1292ca8552 100644 +index 30f61e04ecaf5..9c1292ca85522 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) @@ -319,13 +313,12 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.44.1 - +2.45.1 -From 1a66fcaa0d09216340a495e1e87900833a456f78 Mon Sep 17 00:00:00 2001 +From 67553f37af4ea73f824108a08666b537c68972e5 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 -Subject: [PATCH 06/11] media: v4l2-core: Acquire privacy led in +Subject: [PATCH] media: v4l2-core: Acquire privacy led in v4l2_async_register_subdev() The current call to v4l2_subdev_get_privacy_led() is contained in @@ -341,7 +334,7 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index 3ec323bd528b..b55570a0142c 100644 +index 3ec323bd528b1..b55570a0142cb 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -796,6 +796,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) @@ -356,7 +349,7 @@ index 3ec323bd528b..b55570a0142c 100644 * No reference taken. The reference is held by the device (struct * v4l2_subdev.dev), and async sub-device does not exist independently diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index 89c7192148df..44eca113e772 100644 +index 89c7192148dfb..44eca113e7727 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) @@ -371,13 +364,12 @@ index 89c7192148df..44eca113e772 100644 if (ret < 0) goto out_cleanup; -- -2.44.1 - +2.45.1 -From ba1f6c4984abef2e5d47f07da45018980d5dabc0 Mon Sep 17 00:00:00 2001 +From 82dff76b0fc0e6d8fec20339edcb52fcb3eb1fac Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 -Subject: [PATCH 07/11] platform: x86: int3472: Add MFD cell for tps68470 LED +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED Add MFD cell for tps68470-led. @@ -390,7 +382,7 @@ Patchset: cameras 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index e3e1696e7f0e..423dc555093f 100644 +index e3e1696e7f0ee..423dc555093f7 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -413,13 +405,12 @@ index e3e1696e7f0e..423dc555093f 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.44.1 +2.45.1 - -From f9b20b31ae21ea4762c963a5fb1e6c01bde3e726 Mon Sep 17 00:00:00 2001 +From ac5b449b3e7da53dfff6ab59dc32d9714eb2f106 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 -Subject: [PATCH 08/11] include: mfd: tps68470: Add masks for LEDA and LEDB +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB (TPS68470_ILEDCTL_ENB), and current control mask for LEDB @@ -434,7 +425,7 @@ Patchset: cameras 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 +index 7807fa329db00..2d2abb25b944f 100644 --- a/include/linux/mfd/tps68470.h +++ b/include/linux/mfd/tps68470.h @@ -34,6 +34,7 @@ @@ -455,13 +446,12 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.44.1 - +2.45.1 -From adecf115a9a05225e4eb55172f7d0160a8e50b8f Mon Sep 17 00:00:00 2001 +From 3bdaa0c3e0b7dfa3b441e7d19d3f08ff3708e354 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 -Subject: [PATCH 09/11] leds: tps68470: Add LED control for tps68470 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 There are two LED controllers, LEDA indicator LED and LEDB flash LED for tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, @@ -481,7 +471,7 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 05e6af88b88c..c120eb0b5aa8 100644 +index 05e6af88b88cd..c120eb0b5aa8e 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -909,6 +909,18 @@ config LEDS_TPS6105X @@ -504,7 +494,7 @@ index 05e6af88b88c..c120eb0b5aa8 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index effdfc6f1e95..6ce609b2cdac 100644 +index effdfc6f1e951..6ce609b2cdac6 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o @@ -517,7 +507,7 @@ index effdfc6f1e95..6ce609b2cdac 100644 obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c new file mode 100644 -index 000000000000..35aeb5db89c8 +index 0000000000000..35aeb5db89c8f --- /dev/null +++ b/drivers/leds/leds-tps68470.c @@ -0,0 +1,185 @@ @@ -707,14 +697,13 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.44.1 - +2.45.1 -From 3bcfebe8b0d2ddccbabcfd43a083beec6cc896fe Mon Sep 17 00:00:00 2001 +From 05501de0dab9bc531918dcf2b8aa7e679760fd7b Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 -Subject: [PATCH 10/11] media: staging: ipu3-imgu: Fix multiple calls of - s_stream on stream stop +Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on + stream stop Adapt to 009905e "media: v4l2-subdev: Document and enforce .s_stream() requirements" @@ -724,7 +713,7 @@ Patchset: cameras 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c -index 3df58eb3e882..81aff2d5d898 100644 +index 3df58eb3e8822..81aff2d5d8988 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -538,18 +538,18 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq) @@ -755,24 +744,25 @@ index 3df58eb3e882..81aff2d5d898 100644 r = imgu_s_stream(imgu, false); if (!r) -- -2.44.1 +2.45.1 - -From 5d94cfe88d69350e66c38909a243fcd9f36cb7dd Mon Sep 17 00:00:00 2001 +From c85328d7df3de31a574e42f66192c6a944f48bde Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 -Subject: [PATCH 11/11] media: i2c: dw9719: fix probe error on surface go 2 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. So just add some delay. There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras --- drivers/media/i2c/dw9719.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..0094cfda57ea 100644 +index c626ed845928c..0094cfda57ea8 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c @@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) @@ -786,5 +776,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0013-amd-gpio.patch b/patches/6.9/0014-amd-gpio.patch similarity index 88% rename from patches/6.9/0013-amd-gpio.patch rename to patches/6.9/0014-amd-gpio.patch index d81a92dd67..e9d8371b0a 100644 --- a/patches/6.9/0013-amd-gpio.patch +++ b/patches/6.9/0014-amd-gpio.patch @@ -1,7 +1,7 @@ -From df9777d27612996bc9fb66392c4501ede5bc0b40 Mon Sep 17 00:00:00 2001 +From e0b584d3054d7c69d2e1b4f2ca54e42b79ee5446 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 -Subject: [PATCH 1/2] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 override This patch is the work of Thomas Gleixner and is @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 4bf82dbd2a6b..7a8cb090c656 100644 +index 4bf82dbd2a6b5..7a8cb090c6568 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -63,14 +63,13 @@ index 4bf82dbd2a6b..7a8cb090c656 100644 mp_config_acpi_legacy_irqs(); -- -2.44.1 +2.45.1 - -From 8952d7102223ba7b0509b0883fdd136ad1b4d51a Mon Sep 17 00:00:00 2001 +From dafa7b45eecb1e02dc857158566d2fb3087fa71f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 -Subject: [PATCH 2/2] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 - override quirk +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk The 13" version of the Surface Laptop 4 has the same problem as the 15" version, but uses a different SKU. Add that SKU to the quirk as well. @@ -81,7 +80,7 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 7a8cb090c656..0faafc323e67 100644 +index 7a8cb090c6568..0faafc323e673 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1219,12 +1219,19 @@ static void __init mp_config_acpi_legacy_irqs(void) @@ -106,5 +105,5 @@ index 7a8cb090c656..0faafc323e67 100644 }; -- -2.44.1 +2.45.1 diff --git a/patches/6.9/0014-rtc.patch b/patches/6.9/0015-rtc.patch similarity index 96% rename from patches/6.9/0014-rtc.patch rename to patches/6.9/0015-rtc.patch index 71589a72af..45ac63b8e3 100644 --- a/patches/6.9/0014-rtc.patch +++ b/patches/6.9/0015-rtc.patch @@ -1,4 +1,4 @@ -From a3e68b456c60e19282771143c322f05fb85a6fb7 Mon Sep 17 00:00:00 2001 +From e3e62473f885786f1b57421f5fed86ac5ba402ac Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 1d670dbe4d1d..71c9e375ca1c 100644 +index 1d670dbe4d1dd..71c9e375ca1ca 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -432,6 +432,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, @@ -106,5 +106,5 @@ index 1d670dbe4d1d..71c9e375ca1c 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.44.1 +2.45.1 From 5d6cdf0ed696654d7d01d820b8a24c64c64c6661 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 21:57:33 +0200 Subject: [PATCH 014/236] Update Arch kernel to v6.9.3 --- pkg/arch/kernel/0001-secureboot.patch | 1 + pkg/arch/kernel/0001-surface3-oemb.patch | 1 - pkg/arch/kernel/0002-mwifiex.patch | 1 - pkg/arch/kernel/0002-surface3-oemb.patch | 1 + pkg/arch/kernel/0003-ath10k.patch | 1 - pkg/arch/kernel/0003-mwifiex.patch | 1 + pkg/arch/kernel/0004-ath10k.patch | 1 + pkg/arch/kernel/0004-ipts.patch | 1 - pkg/arch/kernel/0005-ipts.patch | 1 + pkg/arch/kernel/0005-ithc.patch | 1 - pkg/arch/kernel/0006-ithc.patch | 1 + pkg/arch/kernel/0006-surface-sam.patch | 1 - .../kernel/0007-surface-sam-over-hid.patch | 1 - pkg/arch/kernel/0007-surface-sam.patch | 1 + pkg/arch/kernel/0008-surface-button.patch | 1 - .../kernel/0008-surface-sam-over-hid.patch | 1 + pkg/arch/kernel/0009-surface-button.patch | 1 + pkg/arch/kernel/0009-surface-typecover.patch | 1 - pkg/arch/kernel/0010-surface-shutdown.patch | 1 - pkg/arch/kernel/0010-surface-typecover.patch | 1 + pkg/arch/kernel/0011-surface-gpe.patch | 1 - pkg/arch/kernel/0011-surface-shutdown.patch | 1 + pkg/arch/kernel/0012-cameras.patch | 1 - pkg/arch/kernel/0012-surface-gpe.patch | 1 + pkg/arch/kernel/0013-amd-gpio.patch | 1 - pkg/arch/kernel/0013-cameras.patch | 1 + pkg/arch/kernel/0014-amd-gpio.patch | 1 + pkg/arch/kernel/0014-rtc.patch | 1 - pkg/arch/kernel/0015-rtc.patch | 1 + pkg/arch/kernel/PKGBUILD | 64 ++++---- pkg/arch/kernel/config | 148 +++++++++++++----- pkg/arch/kernel/surface.config | 2 +- 32 files changed, 155 insertions(+), 88 deletions(-) create mode 120000 pkg/arch/kernel/0001-secureboot.patch delete mode 120000 pkg/arch/kernel/0001-surface3-oemb.patch delete mode 120000 pkg/arch/kernel/0002-mwifiex.patch create mode 120000 pkg/arch/kernel/0002-surface3-oemb.patch delete mode 120000 pkg/arch/kernel/0003-ath10k.patch create mode 120000 pkg/arch/kernel/0003-mwifiex.patch create mode 120000 pkg/arch/kernel/0004-ath10k.patch delete mode 120000 pkg/arch/kernel/0004-ipts.patch create mode 120000 pkg/arch/kernel/0005-ipts.patch delete mode 120000 pkg/arch/kernel/0005-ithc.patch create mode 120000 pkg/arch/kernel/0006-ithc.patch delete mode 120000 pkg/arch/kernel/0006-surface-sam.patch delete mode 120000 pkg/arch/kernel/0007-surface-sam-over-hid.patch create mode 120000 pkg/arch/kernel/0007-surface-sam.patch delete mode 120000 pkg/arch/kernel/0008-surface-button.patch create mode 120000 pkg/arch/kernel/0008-surface-sam-over-hid.patch create mode 120000 pkg/arch/kernel/0009-surface-button.patch delete mode 120000 pkg/arch/kernel/0009-surface-typecover.patch delete mode 120000 pkg/arch/kernel/0010-surface-shutdown.patch create mode 120000 pkg/arch/kernel/0010-surface-typecover.patch delete mode 120000 pkg/arch/kernel/0011-surface-gpe.patch create mode 120000 pkg/arch/kernel/0011-surface-shutdown.patch delete mode 120000 pkg/arch/kernel/0012-cameras.patch create mode 120000 pkg/arch/kernel/0012-surface-gpe.patch delete mode 120000 pkg/arch/kernel/0013-amd-gpio.patch create mode 120000 pkg/arch/kernel/0013-cameras.patch create mode 120000 pkg/arch/kernel/0014-amd-gpio.patch delete mode 120000 pkg/arch/kernel/0014-rtc.patch create mode 120000 pkg/arch/kernel/0015-rtc.patch diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch new file mode 120000 index 0000000000..6c629b469a --- /dev/null +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -0,0 +1 @@ +../../../patches/6.9/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0001-surface3-oemb.patch b/pkg/arch/kernel/0001-surface3-oemb.patch deleted file mode 120000 index 70abb1cbb5..0000000000 --- a/pkg/arch/kernel/0001-surface3-oemb.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0001-surface3-oemb.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-mwifiex.patch b/pkg/arch/kernel/0002-mwifiex.patch deleted file mode 120000 index bd8ac5ab1c..0000000000 --- a/pkg/arch/kernel/0002-mwifiex.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0002-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3-oemb.patch b/pkg/arch/kernel/0002-surface3-oemb.patch new file mode 120000 index 0000000000..814b883e96 --- /dev/null +++ b/pkg/arch/kernel/0002-surface3-oemb.patch @@ -0,0 +1 @@ +../../../patches/6.9/0002-surface3-oemb.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-ath10k.patch b/pkg/arch/kernel/0003-ath10k.patch deleted file mode 120000 index 0be71beb76..0000000000 --- a/pkg/arch/kernel/0003-ath10k.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0003-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch new file mode 120000 index 0000000000..d3663c2d95 --- /dev/null +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -0,0 +1 @@ +../../../patches/6.9/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch new file mode 120000 index 0000000000..95bd5d4622 --- /dev/null +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -0,0 +1 @@ +../../../patches/6.9/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ipts.patch b/pkg/arch/kernel/0004-ipts.patch deleted file mode 120000 index 7bd11594ed..0000000000 --- a/pkg/arch/kernel/0004-ipts.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0004-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch new file mode 120000 index 0000000000..624485db20 --- /dev/null +++ b/pkg/arch/kernel/0005-ipts.patch @@ -0,0 +1 @@ +../../../patches/6.9/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ithc.patch b/pkg/arch/kernel/0005-ithc.patch deleted file mode 120000 index 51503ed31a..0000000000 --- a/pkg/arch/kernel/0005-ithc.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0005-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch new file mode 120000 index 0000000000..6c0b1f09d9 --- /dev/null +++ b/pkg/arch/kernel/0006-ithc.patch @@ -0,0 +1 @@ +../../../patches/6.9/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-surface-sam.patch b/pkg/arch/kernel/0006-surface-sam.patch deleted file mode 120000 index c8bcc9ae03..0000000000 --- a/pkg/arch/kernel/0006-surface-sam.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0006-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam-over-hid.patch b/pkg/arch/kernel/0007-surface-sam-over-hid.patch deleted file mode 120000 index a99ff8176f..0000000000 --- a/pkg/arch/kernel/0007-surface-sam-over-hid.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0007-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch new file mode 120000 index 0000000000..e9fa7179ce --- /dev/null +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -0,0 +1 @@ +../../../patches/6.9/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-button.patch b/pkg/arch/kernel/0008-surface-button.patch deleted file mode 120000 index 3cddd1a917..0000000000 --- a/pkg/arch/kernel/0008-surface-button.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0008-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch new file mode 120000 index 0000000000..cc03a209dd --- /dev/null +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -0,0 +1 @@ +../../../patches/6.9/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch new file mode 120000 index 0000000000..a2f074fffc --- /dev/null +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -0,0 +1 @@ +../../../patches/6.9/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-typecover.patch b/pkg/arch/kernel/0009-surface-typecover.patch deleted file mode 120000 index 5a55975721..0000000000 --- a/pkg/arch/kernel/0009-surface-typecover.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0009-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-shutdown.patch b/pkg/arch/kernel/0010-surface-shutdown.patch deleted file mode 120000 index 222bcfaabb..0000000000 --- a/pkg/arch/kernel/0010-surface-shutdown.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0010-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch new file mode 120000 index 0000000000..e068d3c47f --- /dev/null +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -0,0 +1 @@ +../../../patches/6.9/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-gpe.patch b/pkg/arch/kernel/0011-surface-gpe.patch deleted file mode 120000 index 705191ef40..0000000000 --- a/pkg/arch/kernel/0011-surface-gpe.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0011-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch new file mode 120000 index 0000000000..284553d689 --- /dev/null +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -0,0 +1 @@ +../../../patches/6.9/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-cameras.patch b/pkg/arch/kernel/0012-cameras.patch deleted file mode 120000 index 478a05bfc0..0000000000 --- a/pkg/arch/kernel/0012-cameras.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0012-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch new file mode 120000 index 0000000000..6d1f1de95b --- /dev/null +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -0,0 +1 @@ +../../../patches/6.9/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-amd-gpio.patch b/pkg/arch/kernel/0013-amd-gpio.patch deleted file mode 120000 index 8128acb79b..0000000000 --- a/pkg/arch/kernel/0013-amd-gpio.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0013-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch new file mode 120000 index 0000000000..6657233011 --- /dev/null +++ b/pkg/arch/kernel/0013-cameras.patch @@ -0,0 +1 @@ +../../../patches/6.9/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch new file mode 120000 index 0000000000..4670c4612c --- /dev/null +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -0,0 +1 @@ +../../../patches/6.9/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-rtc.patch b/pkg/arch/kernel/0014-rtc.patch deleted file mode 120000 index e66855191c..0000000000 --- a/pkg/arch/kernel/0014-rtc.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.8/0014-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch new file mode 120000 index 0000000000..45dfc813e5 --- /dev/null +++ b/pkg/arch/kernel/0015-rtc.patch @@ -0,0 +1 @@ +../../../patches/6.9/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 740c2e9467..366190a458 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.8.8.arch1 +pkgver=6.9.3.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -36,44 +36,46 @@ source=( surface.config # surface specific options arch.config # config changes for linux-surface kernel - 0001-surface3-oemb.patch - 0002-mwifiex.patch - 0003-ath10k.patch - 0004-ipts.patch - 0005-ithc.patch - 0006-surface-sam.patch - 0007-surface-sam-over-hid.patch - 0008-surface-button.patch - 0009-surface-typecover.patch - 0010-surface-shutdown.patch - 0011-surface-gpe.patch - 0012-cameras.patch - 0013-amd-gpio.patch - 0014-rtc.patch + 0001-secureboot.patch + 0002-surface3-oemb.patch + 0003-mwifiex.patch + 0004-ath10k.patch + 0005-ipts.patch + 0006-ithc.patch + 0007-surface-sam.patch + 0008-surface-sam-over-hid.patch + 0009-surface-button.patch + 0010-surface-typecover.patch + 0011-surface-shutdown.patch + 0012-surface-gpe.patch + 0013-cameras.patch + 0014-amd-gpio.patch + 0015-rtc.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('d539ec5682105eb1292bba204f2302e80862947c82b899c9ca38d49021ec30ff' - '0e78254fa2d2718e8912a41047266b9a63aa53fb74198da4389b97fa8bf8c40b' +sha256sums=('a8004dc1982bc7a1e86b7c07918868b48e5eeb746e520d06ce9b1d1356899527' + '3acffee6493e810bd13f042b0a8e97e2b66a977b8ae7ec7c25a604446271860f' '985cd5e0b11538f31887e451c398d226c06ca4b34c5466e93a21ebd65b7b3919' 'd9a981e75adba8f9762555493293e1d162fbe4c6468e734712941852c33a62aa' - 'ee9857e96ee5d871aa557f6d6d142474c26187faa2c21b351bafde065b288fe0' - '12f914866916181f232b4f159a270bce1fc8bd8e93c4f86ae7b18f8d6a777573' - '1984f355569702ff87cfab75682ceb89bfe40ad22c5c4dd8653abe623e000dfb' - '7a38f5da1831757ab9e634a14a0e8a05d05d90e1755e97695d7a58c7e33582f9' - '5119cc60f526f8d0f86f59235fbd18e144932b20437d568350bc92d00b70a647' - 'e53393681a6829cd2ab5873a548780c9d340a635511ad314a65e49555d308bd7' - '9dd041d482eb7f0479487c5fe127f4fd6bec1209d9cd7d77a73f87b205035238' - 'bd32fc7cc18345f027a4fe2af2b249d27470f7b120b1e521dd26008cc34e1e8d' - '02d720e3fffae018fc8719a98135e63c84e8b7f39769bcdee45ddf973a567732' - '6225348b31112a67f5e37a9075363b36c103ba6144083cf4e2d7d83edc77513c' - 'ea0016af33f682a0353738b00c39407b7e1a96a9ccfb04b3904b58143c1953ee' - 'f59a6c1a59699664eeeb5243cb961845944cbc6d1c63353ad9d2ff7d8b593ec3' - '1e620fa5bb90d7a8d4a57d0dc1552b096762a4da4cf1a5ce461d54c3c9b9885f' - '7693cf1df35a47ec8702543d9665f9010a5c7db18a39d9506649e892fd36954f') + '339131528b4075742c4c4d12fbe68f37be775d1f410fd622c6659f3877c1131d' + 'ae82fe11bee1a5aa83d31027f30fa9bfcef072e44a6f0cd2ad04c48646a9e94c' + 'dcf4996a7dd66b1bbc8be3df2ecc1e07586d3f44d41afea1570c12e6a3aa19fb' + '0cd3723970b31418ad8bbe5602bbc22a22e4b7075bec9dab1a32824a3041dba5' + 'a3b41f7aef025d890bd5f067aaf614f2c9b34ae8c50f2a8917b36a2d0883aa7b' + '34f49ba50c93fa4f9991e336fcc56bb8fc604ccf7296c00ddd24ed548b74ad4a' + '35007d1c88b3533e1dd3e67f74e6818bcd4f3a4d1e91938d895f5f12f6ff1471' + '343194f511cd42c7eb03149713587878aa5bfdcc9f53d67b5461e0127c411b8a' + 'aa3cc2dbcef667905b9a03239667afbee18d89747fcca309a8742b493ca69297' + 'a131f277f5e66943d199123e101206b8c29e76dbf2c37eda2d280410901d8ec2' + '973c6eb3bf8a147455f57ccff99e16ba2c64a92ca82d50ba3f12d6217cc29532' + 'fadeb2b97f78a4a6dabd82fb74f55e5087d9b2bcdb4b7cf37df4a27f5f5b6e52' + '551be5c8b7d78a061033fd7c414de9bdd35a24f0564630c77e29378b55894379' + 'e37e84960295a8713966d38734025f8f39395dcb9617c9c202493df05eccdec3' + 'bc5c4dd8b0fbe42fdb4ed336b827d4ee27c9ce7b2f216378e3305a4aed755a85') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index a040589d6f..4872e236ba 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,10 +1,10 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.8.8-arch1 Kernel Configuration +# Linux/x86 6.9.3-arch1 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="gcc (GCC) 13.2.1 20240417" +CONFIG_CC_VERSION_TEXT="gcc (GCC) 14.1.1 20240522" CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=130201 +CONFIG_GCC_VERSION=140101 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y CONFIG_AS_VERSION=24200 @@ -15,7 +15,6 @@ CONFIG_CC_CAN_LINK=y CONFIG_CC_CAN_LINK_STATIC=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y -CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y @@ -90,6 +89,7 @@ CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE=y CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y @@ -182,6 +182,7 @@ CONFIG_RCU_NOCB_CPU=y # CONFIG_RCU_NOCB_CPU_CB_BOOST is not set # CONFIG_TASKS_TRACE_RCU_READ_MB is not set CONFIG_RCU_LAZY=y +# CONFIG_RCU_LAZY_DEFAULT_OFF is not set CONFIG_RCU_DOUBLE_CHECK_CB_TIME=y # end of RCU Subsystem @@ -318,7 +319,8 @@ CONFIG_TRACEPOINTS=y # # Kexec and crash features # -CONFIG_CRASH_CORE=y +CONFIG_CRASH_RESERVE=y +CONFIG_VMCORE_INFO=y CONFIG_KEXEC_CORE=y CONFIG_KEXEC=y CONFIG_KEXEC_FILE=y @@ -367,8 +369,8 @@ CONFIG_CC_HAS_SANE_STACKPROTECTOR=y CONFIG_SMP=y CONFIG_X86_X2APIC=y CONFIG_X86_MPPARSE=y -# CONFIG_GOLDFISH is not set CONFIG_X86_CPU_RESCTRL=y +CONFIG_X86_FRED=y # CONFIG_X86_EXTENDED_PLATFORM is not set CONFIG_X86_INTEL_LPSS=y CONFIG_X86_AMD_PLATFORM_DEVICE=y @@ -544,6 +546,8 @@ CONFIG_HAVE_LIVEPATCH=y # CONFIG_LIVEPATCH is not set # end of Processor type and features +CONFIG_CC_HAS_NAMED_AS=y +CONFIG_USE_X86_SEG_SUPPORT=y CONFIG_CC_HAS_SLS=y CONFIG_CC_HAS_RETURN_THUNK=y CONFIG_CC_HAS_ENTRY_PADDING=y @@ -553,18 +557,18 @@ CONFIG_CALL_PADDING=y CONFIG_HAVE_CALL_THUNKS=y CONFIG_CALL_THUNKS=y CONFIG_PREFIX_SYMBOLS=y -CONFIG_SPECULATION_MITIGATIONS=y -CONFIG_PAGE_TABLE_ISOLATION=y -CONFIG_RETPOLINE=y -CONFIG_RETHUNK=y -CONFIG_CPU_UNRET_ENTRY=y -CONFIG_CALL_DEPTH_TRACKING=y +CONFIG_CPU_MITIGATIONS=y +CONFIG_MITIGATION_PAGE_TABLE_ISOLATION=y +CONFIG_MITIGATION_RETPOLINE=y +CONFIG_MITIGATION_RETHUNK=y +CONFIG_MITIGATION_UNRET_ENTRY=y +CONFIG_MITIGATION_CALL_DEPTH_TRACKING=y # CONFIG_CALL_THUNKS_DEBUG is not set -CONFIG_CPU_IBPB_ENTRY=y -CONFIG_CPU_IBRS_ENTRY=y -CONFIG_CPU_SRSO=y -CONFIG_SLS=y -# CONFIG_GDS_FORCE_MITIGATION is not set +CONFIG_MITIGATION_IBPB_ENTRY=y +CONFIG_MITIGATION_IBRS_ENTRY=y +CONFIG_MITIGATION_SRSO=y +CONFIG_MITIGATION_SLS=y +# CONFIG_MITIGATION_GDS_FORCE is not set CONFIG_MITIGATION_RFDS=y CONFIG_MITIGATION_SPECTRE_BHI=y CONFIG_ARCH_HAS_ADD_PAGES=y @@ -578,6 +582,9 @@ CONFIG_SUSPEND_FREEZER=y CONFIG_HIBERNATE_CALLBACKS=y CONFIG_HIBERNATION=y CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_HIBERNATION_COMP_LZO=y +# CONFIG_HIBERNATION_COMP_LZ4 is not set +CONFIG_HIBERNATION_DEF_COMP="lzo" CONFIG_PM_STD_PARTITION="" CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y @@ -636,7 +643,6 @@ CONFIG_ACPI_HOTPLUG_MEMORY=y CONFIG_ACPI_HOTPLUG_IOAPIC=y CONFIG_ACPI_SBS=m CONFIG_ACPI_HED=y -CONFIG_ACPI_CUSTOM_METHOD=m CONFIG_ACPI_BGRT=y CONFIG_ACPI_NFIT=m # CONFIG_NFIT_SECURITY_DEBUG is not set @@ -649,6 +655,7 @@ CONFIG_ACPI_APEI_GHES=y CONFIG_ACPI_APEI_PCIEAER=y CONFIG_ACPI_APEI_MEMORY_FAILURE=y CONFIG_ACPI_APEI_EINJ=m +CONFIG_ACPI_APEI_EINJ_CXL=y CONFIG_ACPI_APEI_ERST_DEBUG=m CONFIG_ACPI_DPTF=y CONFIG_DPTF_POWER=m @@ -741,13 +748,12 @@ CONFIG_AMD_NB=y # CONFIG_IA32_EMULATION=y # CONFIG_IA32_EMULATION_DEFAULT_DISABLED is not set -# CONFIG_X86_X32_ABI is not set +CONFIG_X86_X32_ABI=y CONFIG_COMPAT_32=y CONFIG_COMPAT=y CONFIG_COMPAT_FOR_U64_ALIGNMENT=y # end of Binary Emulations -CONFIG_HAVE_KVM=y CONFIG_KVM_COMMON=y CONFIG_HAVE_KVM_PFNCACHE=y CONFIG_HAVE_KVM_IRQCHIP=y @@ -758,6 +764,7 @@ CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y CONFIG_KVM_MMIO=y CONFIG_KVM_ASYNC_PF=y CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_READONLY_MEM=y CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y CONFIG_KVM_VFIO=y CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y @@ -785,6 +792,7 @@ CONFIG_AS_SHA256_NI=y CONFIG_AS_TPAUSE=y CONFIG_AS_GFNI=y CONFIG_AS_WRUSS=y +CONFIG_ARCH_CONFIGURES_CPU_MITIGATIONS=y # # General architecture-dependent options @@ -893,8 +901,11 @@ CONFIG_ARCH_MMAP_RND_BITS=32 CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_PAGE_SIZE_4KB=y +CONFIG_PAGE_SIZE_4KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y +CONFIG_PAGE_SHIFT=12 CONFIG_HAVE_OBJTOOL=y CONFIG_HAVE_JUMP_LABEL_HACK=y CONFIG_HAVE_NOINSTR_HACK=y @@ -947,6 +958,8 @@ CONFIG_GCC_PLUGINS=y CONFIG_FUNCTION_ALIGNMENT_4B=y CONFIG_FUNCTION_ALIGNMENT_16B=y CONFIG_FUNCTION_ALIGNMENT=16 +CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT=y +CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y # end of General architecture-dependent options CONFIG_RT_MUTEXES=y @@ -979,6 +992,7 @@ CONFIG_MODULE_COMPRESS_ZSTD=y CONFIG_MODULE_DECOMPRESS=y CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y CONFIG_MODPROBE_PATH="/sbin/modprobe" +# CONFIG_TRIM_UNUSED_KSYMS is not set CONFIG_MODULES_TREE_LOOKUP=y CONFIG_BLOCK=y CONFIG_BLOCK_LEGACY_AUTOLOAD=y @@ -1084,7 +1098,6 @@ CONFIG_ZPOOL=y CONFIG_SWAP=y CONFIG_ZSWAP=y CONFIG_ZSWAP_DEFAULT_ON=y -# CONFIG_ZSWAP_EXCLUSIVE_LOADS_DEFAULT_ON is not set CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y # CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set # CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO is not set @@ -1168,7 +1181,6 @@ CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_USE_PERCPU_NUMA_NODE_ID=y CONFIG_HAVE_SETUP_PER_CPU_AREA=y CONFIG_CMA=y -# CONFIG_CMA_DEBUG is not set CONFIG_CMA_DEBUGFS=y CONFIG_CMA_SYSFS=y CONFIG_CMA_AREAS=7 @@ -1218,7 +1230,7 @@ CONFIG_DAMON=y CONFIG_DAMON_VADDR=y CONFIG_DAMON_PADDR=y CONFIG_DAMON_SYSFS=y -CONFIG_DAMON_DBGFS=y +# CONFIG_DAMON_DBGFS_DEPRECATED is not set CONFIG_DAMON_RECLAIM=y CONFIG_DAMON_LRU_SORT=y # end of Data Access Monitoring @@ -1238,7 +1250,6 @@ CONFIG_SKB_EXTENSIONS=y CONFIG_PACKET=y CONFIG_PACKET_DIAG=m CONFIG_UNIX=y -CONFIG_UNIX_SCM=y CONFIG_AF_UNIX_OOB=y CONFIG_UNIX_DIAG=m CONFIG_TLS=m @@ -1620,6 +1631,7 @@ CONFIG_IP_VS_PE_SIP=m # IP: Netfilter Configuration # CONFIG_NF_DEFRAG_IPV4=m +CONFIG_IP_NF_IPTABLES_LEGACY=m CONFIG_NF_SOCKET_IPV4=m CONFIG_NF_TPROXY_IPV4=m CONFIG_NF_TABLES_IPV4=y @@ -1652,6 +1664,7 @@ CONFIG_IP_NF_TARGET_TTL=m CONFIG_IP_NF_RAW=m CONFIG_IP_NF_SECURITY=m CONFIG_IP_NF_ARPTABLES=m +CONFIG_NFT_COMPAT_ARP=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m # end of IP: Netfilter Configuration @@ -1659,6 +1672,7 @@ CONFIG_IP_NF_ARP_MANGLE=m # # IPv6: Netfilter Configuration # +CONFIG_IP6_NF_IPTABLES_LEGACY=m CONFIG_NF_SOCKET_IPV6=m CONFIG_NF_TPROXY_IPV6=m CONFIG_NF_TABLES_IPV6=y @@ -1696,6 +1710,7 @@ CONFIG_NF_TABLES_BRIDGE=m CONFIG_NFT_BRIDGE_META=m CONFIG_NFT_BRIDGE_REJECT=m CONFIG_NF_CONNTRACK_BRIDGE=m +CONFIG_BRIDGE_NF_EBTABLES_LEGACY=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -1884,7 +1899,6 @@ CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m CONFIG_NET_ACT_SAMPLE=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m @@ -2181,6 +2195,7 @@ CONFIG_ETHTOOL_NETLINK=y CONFIG_HAVE_EISA=y # CONFIG_EISA is not set CONFIG_HAVE_PCI=y +CONFIG_GENERIC_PCI_IOMAP=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y CONFIG_PCIEPORTBUS=y @@ -2273,7 +2288,6 @@ CONFIG_CXL_PORT=m CONFIG_CXL_SUSPEND=y CONFIG_CXL_REGION=y # CONFIG_CXL_REGION_INVALIDATION_TEST is not set -CONFIG_CXL_PMU=m CONFIG_PCCARD=m CONFIG_PCMCIA=m CONFIG_PCMCIA_LOAD_CIS=y @@ -2494,7 +2508,6 @@ CONFIG_MTD_ROM=m # # CONFIG_MTD_COMPLEX_MAPPINGS is not set # CONFIG_MTD_PHYSMAP is not set -# CONFIG_MTD_INTEL_VR_NOR is not set # CONFIG_MTD_PLATRAM is not set # end of Mapping drivers for chip access @@ -2572,6 +2585,7 @@ CONFIG_MTD_UBI_BEB_LIMIT=20 # CONFIG_MTD_UBI_FASTMAP is not set # CONFIG_MTD_UBI_GLUEBI is not set # CONFIG_MTD_UBI_BLOCK is not set +CONFIG_MTD_UBI_NVMEM=m # CONFIG_MTD_HYPERBUS is not set # CONFIG_OF is not set CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y @@ -3063,6 +3077,7 @@ CONFIG_DM_LOG_WRITES=m CONFIG_DM_INTEGRITY=m CONFIG_DM_ZONED=m CONFIG_DM_AUDIT=y +CONFIG_DM_VDO=m CONFIG_TARGET_CORE=m CONFIG_TCM_IBLOCK=m CONFIG_TCM_FILEIO=m @@ -3202,10 +3217,6 @@ CONFIG_NET_DSA_XRS700X=m CONFIG_NET_DSA_XRS700X_I2C=m CONFIG_NET_DSA_XRS700X_MDIO=m CONFIG_NET_DSA_REALTEK=m -# CONFIG_NET_DSA_REALTEK_MDIO is not set -# CONFIG_NET_DSA_REALTEK_SMI is not set -CONFIG_NET_DSA_REALTEK_RTL8365MB=m -CONFIG_NET_DSA_REALTEK_RTL8366RB=m CONFIG_NET_DSA_SMSC_LAN9303=m CONFIG_NET_DSA_SMSC_LAN9303_I2C=m CONFIG_NET_DSA_SMSC_LAN9303_MDIO=m @@ -3367,6 +3378,7 @@ CONFIG_ICE_SWITCHDEV=y CONFIG_ICE_HWTS=y CONFIG_FM10K=m CONFIG_IGC=m +CONFIG_IGC_LEDS=y CONFIG_IDPF=m CONFIG_JME=m CONFIG_NET_VENDOR_ADI=y @@ -3380,6 +3392,7 @@ CONFIG_SKGE_GENESIS=y CONFIG_SKY2=m # CONFIG_SKY2_DEBUG is not set CONFIG_OCTEON_EP=m +CONFIG_OCTEON_EP_VF=m CONFIG_PRESTERA=m CONFIG_PRESTERA_PCI=m CONFIG_NET_VENDOR_MELLANOX=y @@ -3619,7 +3632,10 @@ CONFIG_NXP_CBTX_PHY=m CONFIG_NXP_C45_TJA11XX_PHY=m CONFIG_NXP_TJA11XX_PHY=m CONFIG_NCN26000_PHY=m +CONFIG_QCOM_NET_PHYLIB=m CONFIG_AT803X_PHY=m +CONFIG_QCA83XX_PHY=m +CONFIG_QCA808X_PHY=m CONFIG_QSEMI_PHY=m CONFIG_REALTEK_PHY=m CONFIG_RENESAS_PHY=m @@ -3657,6 +3673,7 @@ CONFIG_CAN_CC770=m CONFIG_CAN_CC770_PLATFORM=m CONFIG_CAN_CTUCANFD=m CONFIG_CAN_CTUCANFD_PCI=m +CONFIG_CAN_ESD_402_PCI=m CONFIG_CAN_IFI_CANFD=m CONFIG_CAN_M_CAN=m CONFIG_CAN_M_CAN_PCI=m @@ -4352,6 +4369,9 @@ CONFIG_TOUCHSCREEN_EGALAX_SERIAL=m CONFIG_TOUCHSCREEN_EXC3000=m CONFIG_TOUCHSCREEN_FUJITSU=m CONFIG_TOUCHSCREEN_GOODIX=m +CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE=m +CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C=m +CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI=m CONFIG_TOUCHSCREEN_HIDEEP=m CONFIG_TOUCHSCREEN_HYCON_HY46XX=m CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX=m @@ -4540,7 +4560,6 @@ CONFIG_VT=y CONFIG_CONSOLE_TRANSLATIONS=y CONFIG_VT_CONSOLE=y CONFIG_VT_CONSOLE_SLEEP=y -CONFIG_HW_CONSOLE=y CONFIG_VT_HW_CONSOLE_BINDING=y CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set @@ -4878,6 +4897,7 @@ CONFIG_PTP_1588_CLOCK_INES=m CONFIG_PTP_1588_CLOCK_KVM=m CONFIG_PTP_1588_CLOCK_IDT82P33=m CONFIG_PTP_1588_CLOCK_IDTCM=m +CONFIG_PTP_1588_CLOCK_FC3W=m CONFIG_PTP_1588_CLOCK_MOCK=m CONFIG_PTP_1588_CLOCK_VMW=m CONFIG_PTP_1588_CLOCK_OCP=m @@ -4994,6 +5014,7 @@ CONFIG_GPIO_TPIC2810=m CONFIG_GPIO_ADP5520=m CONFIG_GPIO_ARIZONA=m CONFIG_GPIO_BD9571MWV=m +CONFIG_GPIO_CROS_EC=m CONFIG_GPIO_CRYSTAL_COVE=m CONFIG_GPIO_DA9052=m CONFIG_GPIO_DA9055=m @@ -5069,6 +5090,7 @@ CONFIG_W1_MASTER_DS2490=m CONFIG_W1_MASTER_DS2482=m CONFIG_W1_MASTER_GPIO=m CONFIG_W1_MASTER_SGI=m +CONFIG_W1_MASTER_UART=m # end of 1-wire Bus Masters # @@ -5213,6 +5235,7 @@ CONFIG_SENSORS_AHT10=m CONFIG_SENSORS_AQUACOMPUTER_D5NEXT=m CONFIG_SENSORS_AS370=m CONFIG_SENSORS_ASC7621=m +CONFIG_SENSORS_ASUS_ROG_RYUJIN=m CONFIG_SENSORS_AXI_FAN_CONTROL=m CONFIG_SENSORS_K8TEMP=m CONFIG_SENSORS_K10TEMP=m @@ -5220,6 +5243,7 @@ CONFIG_SENSORS_FAM15H_POWER=m CONFIG_SENSORS_APPLESMC=m CONFIG_SENSORS_ASB100=m CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CHIPCAP2=m CONFIG_SENSORS_CORSAIR_CPRO=m CONFIG_SENSORS_CORSAIR_PSU=m CONFIG_SENSORS_DRIVETEMP=m @@ -5266,6 +5290,7 @@ CONFIG_SENSORS_LTC4222=m CONFIG_SENSORS_LTC4245=m CONFIG_SENSORS_LTC4260=m CONFIG_SENSORS_LTC4261=m +CONFIG_SENSORS_LTC4282=m CONFIG_SENSORS_MAX1111=m CONFIG_SENSORS_MAX127=m CONFIG_SENSORS_MAX16065=m @@ -5317,6 +5342,7 @@ CONFIG_SENSORS_NCT7802=m CONFIG_SENSORS_NCT7904=m CONFIG_SENSORS_NPCM7XX=m CONFIG_SENSORS_NZXT_KRAKEN2=m +CONFIG_SENSORS_NZXT_KRAKEN3=m CONFIG_SENSORS_NZXT_SMART2=m CONFIG_SENSORS_OCC_P8_I2C=m CONFIG_SENSORS_OCC=m @@ -5363,6 +5389,7 @@ CONFIG_SENSORS_MP5023=m CONFIG_SENSORS_MP5990=m CONFIG_SENSORS_MPQ7932_REGULATOR=y CONFIG_SENSORS_MPQ7932=m +CONFIG_SENSORS_MPQ8785=m CONFIG_SENSORS_PIM4328=m CONFIG_SENSORS_PLI1209BC=m CONFIG_SENSORS_PLI1209BC_REGULATOR=y @@ -5381,6 +5408,7 @@ CONFIG_SENSORS_XDPE152=m CONFIG_SENSORS_XDPE122=m CONFIG_SENSORS_XDPE122_REGULATOR=y CONFIG_SENSORS_ZL6100=m +CONFIG_SENSORS_PT5161L=m CONFIG_SENSORS_SBTSI=m CONFIG_SENSORS_SBRMI=m CONFIG_SENSORS_SHT15=m @@ -5402,6 +5430,7 @@ CONFIG_SENSORS_SCH56XX_COMMON=m CONFIG_SENSORS_SCH5627=m CONFIG_SENSORS_SCH5636=m CONFIG_SENSORS_STTS751=m +CONFIG_SENSORS_SURFACE_FAN=m CONFIG_SENSORS_ADC128D818=m CONFIG_SENSORS_ADS7828=m CONFIG_SENSORS_ADS7871=m @@ -5453,7 +5482,6 @@ CONFIG_THERMAL_NETLINK=y # CONFIG_THERMAL_DEBUGFS is not set CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=100 CONFIG_THERMAL_HWMON=y -CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set # CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set @@ -5516,6 +5544,7 @@ CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y # CONFIG_SOFT_WATCHDOG=m # CONFIG_SOFT_WATCHDOG_PRETIMEOUT is not set +CONFIG_CROS_EC_WATCHDOG=m CONFIG_DA9052_WATCHDOG=m CONFIG_DA9055_WATCHDOG=m CONFIG_DA9063_WATCHDOG=m @@ -6742,8 +6771,8 @@ CONFIG_DVB_DUMMY_FE=m # Graphics support # CONFIG_APERTURE_HELPERS=y -CONFIG_VIDEO_CMDLINE=y -CONFIG_VIDEO_NOMODESET=y +CONFIG_SCREEN_INFO=y +CONFIG_VIDEO=y # CONFIG_AUXDISPLAY is not set # CONFIG_PANEL is not set CONFIG_AGP=y @@ -6763,6 +6792,7 @@ CONFIG_DRM_FBDEV_OVERALLOC=100 CONFIG_DRM_LOAD_EDID_FIRMWARE=y CONFIG_DRM_DISPLAY_HELPER=m CONFIG_DRM_DISPLAY_DP_HELPER=y +CONFIG_DRM_DISPLAY_DP_TUNNEL=y CONFIG_DRM_DISPLAY_HDCP_HELPER=y CONFIG_DRM_DISPLAY_HDMI_HELPER=y CONFIG_DRM_DP_AUX_CHARDEV=y @@ -6831,6 +6861,7 @@ CONFIG_DRM_I915_COMPRESS_ERROR=y CONFIG_DRM_I915_USERPTR=y CONFIG_DRM_I915_GVT_KVMGT=m CONFIG_DRM_I915_PXP=y +CONFIG_DRM_I915_DP_TUNNEL=y CONFIG_DRM_I915_REQUEST_TIMEOUT=20000 CONFIG_DRM_I915_FENCE_TIMEOUT=10000 CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 @@ -6869,6 +6900,7 @@ CONFIG_DRM_PANEL=y # Display Panels # CONFIG_DRM_PANEL_AUO_A030JTN01=m +CONFIG_DRM_PANEL_ILITEK_ILI9341=m CONFIG_DRM_PANEL_ORISETECH_OTA5601A=m CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m CONFIG_DRM_PANEL_WIDECHIPS_WS2401=m @@ -6999,6 +7031,7 @@ CONFIG_LCD_HX8357=m CONFIG_LCD_OTM3225A=m CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_KTD253=m +CONFIG_BACKLIGHT_KTD2801=m CONFIG_BACKLIGHT_KTZ8866=m CONFIG_BACKLIGHT_LM3533=m CONFIG_BACKLIGHT_PWM=m @@ -7212,6 +7245,7 @@ CONFIG_SND_HDA_PATCH_LOADER=y CONFIG_SND_HDA_CIRRUS_SCODEC=m CONFIG_SND_HDA_SCODEC_CS35L41=m CONFIG_SND_HDA_CS_DSP_CONTROLS=m +CONFIG_SND_HDA_SCODEC_COMPONENT=m CONFIG_SND_HDA_SCODEC_CS35L41_I2C=m CONFIG_SND_HDA_SCODEC_CS35L41_SPI=m CONFIG_SND_HDA_SCODEC_CS35L56=m @@ -7314,7 +7348,10 @@ CONFIG_SND_AMD_ASOC_ACP70=m CONFIG_SND_SOC_AMD_MACH_COMMON=m CONFIG_SND_SOC_AMD_LEGACY_MACH=m CONFIG_SND_SOC_AMD_SOF_MACH=m +CONFIG_SND_AMD_SOUNDWIRE_ACPI=m CONFIG_SND_SOC_AMD_RPL_ACP6x=m +CONFIG_SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE=m +CONFIG_SND_SOC_AMD_SOUNDWIRE=m CONFIG_SND_SOC_AMD_PS=m CONFIG_SND_SOC_AMD_PS_MACH=m CONFIG_SND_ATMEL_SOC=m @@ -7466,6 +7503,8 @@ CONFIG_SND_SOC_SOF_AMD_RENOIR=m CONFIG_SND_SOC_SOF_AMD_VANGOGH=m CONFIG_SND_SOC_SOF_AMD_REMBRANDT=m CONFIG_SND_SOC_SOF_ACP_PROBES=m +CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE=m +CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE=m CONFIG_SND_SOC_SOF_AMD_ACP63=m CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL=y CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC=m @@ -7556,6 +7595,7 @@ CONFIG_SND_SOC_BD28623=m # CONFIG_SND_SOC_BT_SCO is not set CONFIG_SND_SOC_CHV3_CODEC=m CONFIG_SND_SOC_CROS_EC_CODEC=m +CONFIG_SND_SOC_CS_AMP_LIB=m CONFIG_SND_SOC_CS35L32=m CONFIG_SND_SOC_CS35L33=m CONFIG_SND_SOC_CS35L34=m @@ -7756,6 +7796,8 @@ CONFIG_SND_SOC_WCD_MBHC=m CONFIG_SND_SOC_WCD934X=m CONFIG_SND_SOC_WCD938X=m CONFIG_SND_SOC_WCD938X_SDW=m +CONFIG_SND_SOC_WCD939X=m +CONFIG_SND_SOC_WCD939X_SDW=m CONFIG_SND_SOC_WM5102=m CONFIG_SND_SOC_WM8510=m CONFIG_SND_SOC_WM8523=m @@ -8023,6 +8065,7 @@ CONFIG_USB_DEFAULT_PERSIST=y # CONFIG_USB_OTG_PRODUCTLIST is not set CONFIG_USB_LEDS_TRIGGER_USBPORT=m CONFIG_USB_AUTOSUSPEND_DELAY=2 +CONFIG_USB_DEFAULT_AUTHORIZATION_MODE=1 CONFIG_USB_MON=m # @@ -8410,6 +8453,7 @@ CONFIG_TYPEC_MUX_FSA4480=m CONFIG_TYPEC_MUX_GPIO_SBU=m CONFIG_TYPEC_MUX_PI3USB30532=m CONFIG_TYPEC_MUX_INTEL_PMC=m +CONFIG_TYPEC_MUX_IT5205=m CONFIG_TYPEC_MUX_NB7VPQ904M=m CONFIG_TYPEC_MUX_PTN36502=m CONFIG_TYPEC_MUX_WCD939X_USBSS=m @@ -8485,6 +8529,7 @@ CONFIG_MEMSTICK_JMICRON_38X=m CONFIG_MEMSTICK_R592=m CONFIG_MEMSTICK_REALTEK_PCI=m CONFIG_MEMSTICK_REALTEK_USB=m +CONFIG_LEDS_EXPRESSWIRE=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_FLASH=m @@ -8909,7 +8954,7 @@ CONFIG_VIRTIO_VFIO_PCI=m # end of VFIO support for PCI devices CONFIG_VFIO_MDEV=m -CONFIG_IRQ_BYPASS_MANAGER=m +CONFIG_IRQ_BYPASS_MANAGER=y CONFIG_VIRT_DRIVERS=y CONFIG_VMGENID=y CONFIG_VBOXGUEST=m @@ -9087,6 +9132,7 @@ CONFIG_KS7010=m CONFIG_PI433=m CONFIG_FIELDBUS_DEV=m # CONFIG_VME_BUS is not set +# CONFIG_GOLDFISH is not set CONFIG_CHROME_PLATFORMS=y CONFIG_CHROMEOS_ACPI=m CONFIG_CHROMEOS_LAPTOP=m @@ -9335,6 +9381,7 @@ CONFIG_IOMMU_DEFAULT_DMA_LAZY=y # CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set CONFIG_IOMMU_DMA=y CONFIG_IOMMU_SVA=y +CONFIG_IOMMU_IOPF=y CONFIG_AMD_IOMMU=y CONFIG_DMAR_TABLE=y CONFIG_INTEL_IOMMU=y @@ -9510,6 +9557,7 @@ CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 CONFIG_IIO_SW_DEVICE=m CONFIG_IIO_SW_TRIGGER=m CONFIG_IIO_TRIGGERED_EVENT=m +CONFIG_IIO_BACKEND=m # # Accelerometers @@ -9536,6 +9584,7 @@ CONFIG_BMC150_ACCEL=m CONFIG_BMC150_ACCEL_I2C=m CONFIG_BMC150_ACCEL_SPI=m CONFIG_BMI088_ACCEL=m +CONFIG_BMI088_ACCEL_I2C=m CONFIG_BMI088_ACCEL_SPI=m CONFIG_DA280=m CONFIG_DA311=m @@ -9603,6 +9652,8 @@ CONFIG_AD7887=m CONFIG_AD7923=m CONFIG_AD7949=m CONFIG_AD799X=m +CONFIG_AD9467=m +CONFIG_ADI_AXI_ADC=m CONFIG_AXP20X_ADC=m CONFIG_AXP288_ADC=m CONFIG_CC10001_ADC=m @@ -9638,6 +9689,7 @@ CONFIG_MEDIATEK_MT6370_ADC=m CONFIG_MEN_Z188_ADC=m CONFIG_MP2629_ADC=m CONFIG_NAU7802=m +CONFIG_PAC1934=m CONFIG_PALMAS_GPADC=m CONFIG_RICHTEK_RTQ6056=m CONFIG_SD_ADC_MODULATOR=m @@ -9651,6 +9703,7 @@ CONFIG_TI_ADC161S626=m CONFIG_TI_ADS1015=m CONFIG_TI_ADS7924=m CONFIG_TI_ADS1100=m +CONFIG_TI_ADS1298=m CONFIG_TI_ADS7950=m CONFIG_TI_ADS8344=m CONFIG_TI_ADS8688=m @@ -9825,6 +9878,7 @@ CONFIG_AD9523=m CONFIG_ADF4350=m CONFIG_ADF4371=m CONFIG_ADF4377=m +CONFIG_ADMFM2000=m CONFIG_ADMV1013=m CONFIG_ADMV1014=m CONFIG_ADMV4420=m @@ -10089,6 +10143,8 @@ CONFIG_MPL115_I2C=m CONFIG_MPL115_SPI=m CONFIG_MPL3115=m CONFIG_MPRLS0025PA=m +CONFIG_MPRLS0025PA_I2C=m +CONFIG_MPRLS0025PA_SPI=m CONFIG_MS5611=m CONFIG_MS5611_I2C=m CONFIG_MS5611_SPI=m @@ -10198,6 +10254,7 @@ CONFIG_IPACK_BUS=m CONFIG_BOARD_TPCI200=m CONFIG_SERIAL_IPOCTAL=m CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_GPIO=m CONFIG_RESET_TI_SYSCON=m CONFIG_RESET_TI_TPS380X=m @@ -10238,11 +10295,14 @@ CONFIG_MCB_LPC=m # Performance monitor support # CONFIG_DWC_PCIE_PMU=m +CONFIG_CXL_PMU=m # end of Performance monitor support CONFIG_RAS=y CONFIG_RAS_CEC=y # CONFIG_RAS_CEC_DEBUG is not set +CONFIG_AMD_ATL=m +CONFIG_RAS_FMPM=m CONFIG_USB4=m # CONFIG_USB4_DEBUGFS_WRITE is not set # CONFIG_USB4_DMA_TEST is not set @@ -10385,6 +10445,9 @@ CONFIG_XFS_QUOTA=y CONFIG_XFS_POSIX_ACL=y CONFIG_XFS_RT=y CONFIG_XFS_DRAIN_INTENTS=y +CONFIG_XFS_LIVE_HOOKS=y +CONFIG_XFS_MEMORY_BUFS=y +CONFIG_XFS_BTREE_IN_MEM=y CONFIG_XFS_ONLINE_SCRUB=y # CONFIG_XFS_ONLINE_SCRUB_STATS is not set CONFIG_XFS_ONLINE_REPAIR=y @@ -10458,6 +10521,7 @@ CONFIG_FUSE_FS=y CONFIG_CUSE=m CONFIG_VIRTIO_FS=y CONFIG_FUSE_DAX=y +CONFIG_FUSE_PASSTHROUGH=y CONFIG_OVERLAY_FS=m CONFIG_OVERLAY_FS_REDIRECT_DIR=y # CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW is not set @@ -10500,11 +10564,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_FAT_DEFAULT_UTF8=y CONFIG_EXFAT_FS=m CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" -# CONFIG_NTFS_FS is not set CONFIG_NTFS3_FS=m # CONFIG_NTFS3_64BIT_CLUSTER is not set CONFIG_NTFS3_LZX_XPRESS=y CONFIG_NTFS3_FS_POSIX_ACL=y +# CONFIG_NTFS_FS is not set # end of DOS/FAT/EXFAT/NT Filesystems # @@ -10891,6 +10955,7 @@ CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_ALGAPI2=y CONFIG_CRYPTO_AEAD=m CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SIG=y CONFIG_CRYPTO_SIG2=y CONFIG_CRYPTO_SKCIPHER=y CONFIG_CRYPTO_SKCIPHER2=y @@ -11023,7 +11088,7 @@ CONFIG_CRYPTO_CRC64_ROCKSOFT=y # Compression # CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_LZO=m +CONFIG_CRYPTO_LZO=y CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m @@ -11125,6 +11190,7 @@ CONFIG_CRYPTO_DEV_QAT_420XX=m CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m CONFIG_CRYPTO_DEV_QAT_C3XXXVF=m CONFIG_CRYPTO_DEV_QAT_C62XVF=m +# CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION is not set CONFIG_CRYPTO_DEV_IAA_CRYPTO=m # CONFIG_CRYPTO_DEV_IAA_CRYPTO_STATS is not set CONFIG_CRYPTO_DEV_CHELSIO=m @@ -11175,7 +11241,6 @@ CONFIG_GENERIC_NET_UTILS=y CONFIG_CORDIC=m # CONFIG_PRIME_NUMBERS is not set CONFIG_RATIONAL=y -CONFIG_GENERIC_PCI_IOMAP=y CONFIG_GENERIC_IOMAP=y CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y CONFIG_ARCH_HAS_FAST_MULTIPLIER=y @@ -11413,7 +11478,7 @@ CONFIG_DEBUG_FS_ALLOW_ALL=y # CONFIG_DEBUG_FS_ALLOW_NONE is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set -CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +CONFIG_ARCH_HAS_UBSAN=y # CONFIG_UBSAN is not set CONFIG_HAVE_ARCH_KCSAN=y CONFIG_HAVE_KCSAN_COMPILER=y @@ -11464,6 +11529,7 @@ CONFIG_ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP=y CONFIG_HAVE_ARCH_KASAN=y CONFIG_HAVE_ARCH_KASAN_VMALLOC=y CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_KASAN_SW_TAGS=y CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y # CONFIG_KASAN is not set CONFIG_HAVE_ARCH_KFENCE=y @@ -11710,8 +11776,6 @@ CONFIG_RUNTIME_TESTING_MENU=y # CONFIG_ATOMIC64_SELFTEST is not set CONFIG_ASYNC_RAID6_TEST=m # CONFIG_TEST_HEXDUMP is not set -# CONFIG_STRING_SELFTEST is not set -# CONFIG_TEST_STRING_HELPERS is not set # CONFIG_TEST_KSTRTOX is not set # CONFIG_TEST_PRINTF is not set # CONFIG_TEST_SCANF is not set diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index 8e963d737e..f20c155d2a 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.8.config \ No newline at end of file +../../../configs/surface-6.9.config \ No newline at end of file From c63c76cbc31d6b4d8c2db5564073c712c42569ee Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 21:58:51 +0200 Subject: [PATCH 015/236] Update Debian kernel to v6.9.3 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 065db15a13..10ea134422 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.8.8" +KERNEL_VERSION="6.9.3" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From c67bbcf9bfa5541fe6053f2141c8be878c5592ea Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 11 Jun 2024 00:04:47 +0200 Subject: [PATCH 016/236] config: Build in UFS modules --- configs/surface-6.6.config | 6 ++++++ configs/surface-6.8.config | 6 ++++++ configs/surface-6.9.config | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/configs/surface-6.6.config b/configs/surface-6.6.config index fedb251cf3..05628a9957 100644 --- a/configs/surface-6.6.config +++ b/configs/surface-6.6.config @@ -65,6 +65,12 @@ CONFIG_VIDEO_OV8865=m ## CONFIG_APDS9960=m +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + ## ## Other Drivers ## diff --git a/configs/surface-6.8.config b/configs/surface-6.8.config index fedb251cf3..05628a9957 100644 --- a/configs/surface-6.8.config +++ b/configs/surface-6.8.config @@ -65,6 +65,12 @@ CONFIG_VIDEO_OV8865=m ## CONFIG_APDS9960=m +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + ## ## Other Drivers ## diff --git a/configs/surface-6.9.config b/configs/surface-6.9.config index fedb251cf3..05628a9957 100644 --- a/configs/surface-6.9.config +++ b/configs/surface-6.9.config @@ -65,6 +65,12 @@ CONFIG_VIDEO_OV8865=m ## CONFIG_APDS9960=m +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + ## ## Other Drivers ## From 9a5ca204b2c661f956a9ff31ccad64df1a5b73b9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 11 Jun 2024 00:07:58 +0200 Subject: [PATCH 017/236] Bump Arch and Debian kernel releases --- pkg/arch/kernel/PKGBUILD | 4 ++-- pkg/debian/kernel/version.conf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 366190a458..95237098f8 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -4,7 +4,7 @@ pkgbase=linux-surface pkgver=6.9.3.arch1 -pkgrel=1 +pkgrel=2 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -59,7 +59,7 @@ validpgpkeys=( ) sha256sums=('a8004dc1982bc7a1e86b7c07918868b48e5eeb746e520d06ce9b1d1356899527' '3acffee6493e810bd13f042b0a8e97e2b66a977b8ae7ec7c25a604446271860f' - '985cd5e0b11538f31887e451c398d226c06ca4b34c5466e93a21ebd65b7b3919' + '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' 'd9a981e75adba8f9762555493293e1d162fbe4c6468e734712941852c33a62aa' '339131528b4075742c4c4d12fbe68f37be775d1f410fd622c6659f3877c1131d' 'ae82fe11bee1a5aa83d31027f30fa9bfcef072e44a6f0cd2ad04c48646a9e94c' diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 10ea134422..e43b4fc009 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ KERNEL_VERSION="6.9.3" -KERNEL_REVISION="1" +KERNEL_REVISION="2" KERNEL_LOCALVERSION="-surface" From 312dae71d425bba0df8074aedb34585cc79af385 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 11 Jun 2024 20:56:27 +0200 Subject: [PATCH 018/236] pkg/arch: Do not force-build-in serial drivers The current v6.9 patches include a fix for the serdev driver probe issue. Therefore, we don't need to build in the serial driver modules any longer. --- pkg/arch/kernel/arch.config | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/arch/kernel/arch.config b/pkg/arch/kernel/arch.config index 4580db09ee..f2912ab075 100644 --- a/pkg/arch/kernel/arch.config +++ b/pkg/arch/kernel/arch.config @@ -26,14 +26,10 @@ CONFIG_ANDROID_BINDERFS=y CONFIG_ANDROID_BINDER_DEVICES="" ## -## Build-in basic pinctrl/serial modules to prevent race-conditions in drivers -## relying on them (like soc-button-array, SAM) +## Build-in basic pinctrl modules to prevent race-conditions in drivers +## relying on them (like soc-button-array) ## -CONFIG_SERIAL_8250_DW=y -CONFIG_MFD_INTEL_LPSS=y -CONFIG_MFD_INTEL_LPSS_PCI=y - CONFIG_PINCTRL_INTEL=y CONFIG_PINCTRL_ALDERLAKE=y CONFIG_PINCTRL_CANNONLAKE=y From d26dcab5dcc88ae7ad6e08b3038075ece24127ea Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:16:41 +0200 Subject: [PATCH 019/236] Update v6.9 patches Changes: - Pull in patch to fix serial port suspend. See - https://github.com/linux-surface/linux-surface/issues/1412#issuecomment-2161878306 - https://lore.kernel.org/lkml/20240531080914.v3.1.I2395e66cf70c6e67d774c56943825c289b9c13e4@changeid/ - Enable fan monitoring and profile switching on the Surface Laptop 5 and Surface Laptop Studio 2. See - https://github.com/linux-surface/linux-surface/issues/1463 Links: - kernel: https://github.com/linux-surface/kernel/commit/c982d42b71168279b57493dd39206b73f253a9b1 --- patches/6.9/0001-secureboot.patch | 2 +- patches/6.9/0002-surface3-oemb.patch | 2 +- patches/6.9/0003-mwifiex.patch | 6 +- patches/6.9/0004-ath10k.patch | 2 +- patches/6.9/0005-ipts.patch | 10 +-- patches/6.9/0006-ithc.patch | 6 +- patches/6.9/0007-surface-sam.patch | 78 ++++++++++++++++++--- patches/6.9/0008-surface-sam-over-hid.patch | 10 +-- patches/6.9/0009-surface-button.patch | 4 +- patches/6.9/0010-surface-typecover.patch | 12 ++-- patches/6.9/0011-surface-shutdown.patch | 4 +- patches/6.9/0012-surface-gpe.patch | 2 +- patches/6.9/0013-cameras.patch | 26 +++---- patches/6.9/0014-amd-gpio.patch | 4 +- patches/6.9/0015-rtc.patch | 2 +- 15 files changed, 114 insertions(+), 56 deletions(-) diff --git a/patches/6.9/0001-secureboot.patch b/patches/6.9/0001-secureboot.patch index 223c1ab2c0..3f9fae137f 100644 --- a/patches/6.9/0001-secureboot.patch +++ b/patches/6.9/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 24686c656a230f642f8ed6c09c184660c08cf46c Mon Sep 17 00:00:00 2001 +From def57db20e3390d77283c4715bf277c4b16073ff Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag diff --git a/patches/6.9/0002-surface3-oemb.patch b/patches/6.9/0002-surface3-oemb.patch index 211d83cd19..07b88d1dc1 100644 --- a/patches/6.9/0002-surface3-oemb.patch +++ b/patches/6.9/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From a494cdb84ee162accff966a0012992e36e4b0c0a Mon Sep 17 00:00:00 2001 +From 9517aa6b06c90854df9f7e4a8b633f4f2dedfe9b Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.9/0003-mwifiex.patch b/patches/6.9/0003-mwifiex.patch index ca64439b05..c52004110f 100644 --- a/patches/6.9/0003-mwifiex.patch +++ b/patches/6.9/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 1abf1feb3b521abe9f9c9e8d68d2014e90ecb20d Mon Sep 17 00:00:00 2001 +From c4550d9917b83ef96aacf4f7162797c1566fd4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5bf..5d30ae39d65ec 100644 -- 2.45.1 -From 0574bff98f5f5af132783f8f72e8ef22e3f36097 Mon Sep 17 00:00:00 2001 +From 0b8f67a82e0256c352d02f53156f7f278a5f5f9e Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65ec..c14eb56eb9118 100644 -- 2.45.1 -From 8a4ee131ced8068371a8fa09da17d82414e6d835 Mon Sep 17 00:00:00 2001 +From b5f2d2733bdf90dc863f63817280e77d5566aa34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.9/0004-ath10k.patch b/patches/6.9/0004-ath10k.patch index e8874603ac..7d1e817310 100644 --- a/patches/6.9/0004-ath10k.patch +++ b/patches/6.9/0004-ath10k.patch @@ -1,4 +1,4 @@ -From fc56de38d725edc7c3856c2a2d369e1f170f202f Mon Sep 17 00:00:00 2001 +From 9f3a99c15c226a002ef10ca9f494d49397729290 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.9/0005-ipts.patch b/patches/6.9/0005-ipts.patch index 3b79e84de7..ab53870c35 100644 --- a/patches/6.9/0005-ipts.patch +++ b/patches/6.9/0005-ipts.patch @@ -1,4 +1,4 @@ -From ee272e8a81f073b5475a3bb2c3085b55f181bc24 Mon Sep 17 00:00:00 2001 +From 91720b1952e1ff5a54820c2a1653b78547394358 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -23,7 +23,7 @@ index c3a6657dcd4a2..82eef2f4eb0a8 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 7f59dd38c32f5..a56ad5b3f7790 100644 +index 6589635f8ba32..a1df48a434e2f 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -37,7 +37,7 @@ index 7f59dd38c32f5..a56ad5b3f7790 100644 -- 2.45.1 -From 8536601cfc6d7671f4c11cab4dca57674f59b349 Mon Sep 17 00:00:00 2001 +From 89b8b2d10c6621b08e331bf3400f18be0c3b220e Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e4a03588a8a0f..61bc54299a591 100644 -- 2.45.1 -From 664128ab9984f6c774d4064548d9b247041d2520 Mon Sep 17 00:00:00 2001 +From c57990a8a2940d822267089e497ea71d87b8d91b Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3236,7 +3236,7 @@ index 0000000000000..1f966b8b32c45 -- 2.45.1 -From ee8823ff409dc4507cc2f7c8f8c474735b005938 Mon Sep 17 00:00:00 2001 +From eec87febb5aedae2e6bcd20cb9539ea2aff4bcdb Mon Sep 17 00:00:00 2001 From: Jasmin Huber Date: Mon, 15 Apr 2024 10:22:55 +0200 Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile diff --git a/patches/6.9/0006-ithc.patch b/patches/6.9/0006-ithc.patch index 2f9e19ba26..3eb8993010 100644 --- a/patches/6.9/0006-ithc.patch +++ b/patches/6.9/0006-ithc.patch @@ -1,4 +1,4 @@ -From 4b17942da35790b0e703a87267545f5a9f08e1cf Mon Sep 17 00:00:00 2001 +From 9753b4d8abe343fb74f7305ea52dcb1839b70409 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 566297bc87ddb..a8cd8f12d5937 100644 -- 2.45.1 -From 14baff1c79b6499868b48e6fb4ada851db35c941 Mon Sep 17 00:00:00 2001 +From e58e432524ab069a1582b38632f9fed86754708a Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -1818,7 +1818,7 @@ index 0000000000000..028e55a4ec53e -- 2.45.1 -From 2537922b2f0c1d0002a2afe6d0fc79695add8e60 Mon Sep 17 00:00:00 2001 +From 822127904dec578540affeb80b26a46744333029 Mon Sep 17 00:00:00 2001 From: quo Date: Fri, 19 Apr 2024 22:11:09 +0200 Subject: [PATCH] hid: ithc: Update from quo/ithc-linux diff --git a/patches/6.9/0007-surface-sam.patch b/patches/6.9/0007-surface-sam.patch index a3f41abd1c..83f892e5af 100644 --- a/patches/6.9/0007-surface-sam.patch +++ b/patches/6.9/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From b4563a0da733d5759de36d9e555ce81324dca286 Mon Sep 17 00:00:00 2001 +From 619f5f1754e755935ce38ea2ada145ba19dcff6a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 May 2024 16:15:49 +0200 Subject: [PATCH] serial: Clear UPF_DEAD before calling @@ -79,7 +79,7 @@ index c476d884356db..b47a277978a0b 100644 -- 2.45.1 -From 0864ded554efe90dd9603b61e82c604481ee5125 Mon Sep 17 00:00:00 2001 +From 51695a151d5b9e7468911944a8357427228efc57 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 5 May 2024 21:07:50 +0800 Subject: [PATCH] platform/surface: aggregator: Log critical errors during SAM @@ -215,7 +215,7 @@ index ba550eaa06fcf..797d0645bd77f 100644 -- 2.45.1 -From d44985653441ba783a830bd5efde2fcf3a3ea271 Mon Sep 17 00:00:00 2001 +From f71471eace9cad92cd1c57d3bc214c6fc18190aa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 19 Apr 2024 20:41:47 +0200 Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is @@ -270,7 +270,7 @@ index 7fc602e01487d..7e89f547999b2 100644 -- 2.45.1 -From 6b6f860bbef0ba3f10f8dc151ac4e27d0a34c223 Mon Sep 17 00:00:00 2001 +From 84059069e8000f85666ec080258a5dc66a255e9d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Oct 2023 14:57:11 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -303,7 +303,7 @@ index 035d6b4105cd6..74688a2ed4b2e 100644 -- 2.45.1 -From 31b312c25822404e52a81de2525da5c7bae12864 Mon Sep 17 00:00:00 2001 +From 48129c8bacd2d53c44d08f2510bad0d23daef42e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 19:47:00 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -373,7 +373,7 @@ index 74688a2ed4b2e..f02a933160ff2 100644 -- 2.45.1 -From 42f6d14bda5e69c2b5a8d27cfcbd063a5922f876 Mon Sep 17 00:00:00 2001 +From 40519c80a360c0113c5e8f689b4c3d586613c162 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 20:05:57 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -430,7 +430,7 @@ index f02a933160ff2..34df1bdad83bd 100644 -- 2.45.1 -From 88fda328aea3bb7077cd39f854148276dcffcea3 Mon Sep 17 00:00:00 2001 +From b80d055e4865d17e11d17d53501409fa87555345 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -658,7 +658,7 @@ index 0000000000000..48c3e826713f6 -- 2.45.1 -From 17f0ec6ef1bc95e152af3a9f2b05ea669c75d24a Mon Sep 17 00:00:00 2001 +From 32fda2a1c96376a27be0e0c57755711fa662cd52 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -853,7 +853,7 @@ index 48c3e826713f6..4c08926139dbf 100644 -- 2.45.1 -From 54bfa02fe865b9f22d79b112a5244ce81e4961f1 Mon Sep 17 00:00:00 2001 +From c0169d071bb08ca5ef4551bbe166120f37047900 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:21:12 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -896,7 +896,7 @@ index 34df1bdad83bd..c0bf0cadcd258 100644 -- 2.45.1 -From 06c4b5ac6b6357227e45c53643729140d794b48d Mon Sep 17 00:00:00 2001 +From 01e4b0bb9383af68d9396e20fb749b997a111de3 Mon Sep 17 00:00:00 2001 From: Ivor Wanders Date: Sat, 16 Dec 2023 15:56:39 -0500 Subject: [PATCH] platform/surface: platform_profile: add fan profile switching @@ -1223,3 +1223,61 @@ index a5a3941b3f43a..e54d0a8f7daa5 100644 -- 2.45.1 +From 300366539fe3053b4bfaf9ce31d571c8a3bf0ac0 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Mon, 10 Jun 2024 21:47:47 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal + sensor support for Surface Laptop 5 + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 07a4c4e1120d3..4dc79f791d390 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -265,7 +265,9 @@ static const struct software_node *ssam_node_group_sl5[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_perf_profile, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, + &ssam_node_hid_main_keyboard, + &ssam_node_hid_main_touchpad, + &ssam_node_hid_main_iid5, +-- +2.45.1 + +From 2942f156e20ee4deead0441bfb665f22bb0e4a87 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Mon, 10 Jun 2024 21:48:02 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal + sensor support for Surface Laptop Studio 2 + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 4dc79f791d390..77f903a04d128 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -312,7 +312,9 @@ static const struct software_node *ssam_node_group_sls2[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_perf_profile, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, + &ssam_node_pos_tablet_switch, + &ssam_node_hid_sam_keyboard, + &ssam_node_hid_sam_penstash, +-- +2.45.1 + diff --git a/patches/6.9/0008-surface-sam-over-hid.patch b/patches/6.9/0008-surface-sam-over-hid.patch index 49133c160a..9641b25d14 100644 --- a/patches/6.9/0008-surface-sam-over-hid.patch +++ b/patches/6.9/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From bf55987e82f9ae913b51a6a269fc1a397930f049 Mon Sep 17 00:00:00 2001 +From d0d9bd15ba1c1bbe0ac57888e0592f3a39cc8268 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,10 +55,10 @@ Patchset: surface-sam-over-hid 1 file changed, 35 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index d6037a3286690..a290ebc77aea2 100644 +index 14ae0cfc325ef..a3a9f81fb47ff 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c -@@ -628,6 +628,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, +@@ -639,6 +639,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, return (ret == 1) ? 0 : -EIO; } @@ -87,7 +87,7 @@ index d6037a3286690..a290ebc77aea2 100644 static acpi_status i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, -@@ -729,6 +751,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, +@@ -740,6 +762,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, } break; @@ -110,7 +110,7 @@ index d6037a3286690..a290ebc77aea2 100644 -- 2.45.1 -From ebfda7ad73dd90971be10e9d6f59c51c781accbb Mon Sep 17 00:00:00 2001 +From 9ff8e9c9025f8a0a7e4b0b8cd1e526a4f4ff331f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.9/0009-surface-button.patch b/patches/6.9/0009-surface-button.patch index 232b6ba310..e4f35aa787 100644 --- a/patches/6.9/0009-surface-button.patch +++ b/patches/6.9/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 1e315f586b0b2bc375b96bb538a3be4c0b09d1ea Mon Sep 17 00:00:00 2001 +From 23a728a730706febe949f3cb7d34c35e91f77be0 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index f6d060377d189..b8603f74eb286 100644 -- 2.45.1 -From ac551644781bce2145c901b16779114b273c4d49 Mon Sep 17 00:00:00 2001 +From 85b8dbc9527a74be5f87d2148c79242219cef174 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.9/0010-surface-typecover.patch b/patches/6.9/0010-surface-typecover.patch index 1a6441472e..62da601e36 100644 --- a/patches/6.9/0010-surface-typecover.patch +++ b/patches/6.9/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From dbe49f128699931e317242ba589c1c22a63eed5f Mon Sep 17 00:00:00 2001 +From 876520d57f820abe10ebac4ea016c696a1508196 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index b4783574b8e66..360970620589a 100644 -- 2.45.1 -From 89a3afeae85bd60a46bc4c2f0b23fb886452f5be Mon Sep 17 00:00:00 2001 +From 0de3d958b4cc82cd4e2814504f9125830d0807c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 04a014cd2a2f6..89c9b00e63712 100644 +index 56fc78841f245..a266449065a0a 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -257,7 +257,7 @@ index 04a014cd2a2f6..89c9b00e63712 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2229,6 +2320,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2235,6 +2326,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -272,7 +272,7 @@ index 04a014cd2a2f6..89c9b00e63712 100644 -- 2.45.1 -From 3e3ecb44c93d8259a2a9e97ccfa09eb5b54d1a90 Mon Sep 17 00:00:00 2001 +From 058286622357a3cdc684076c9bbae4dbbb58c5b0 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -301,7 +301,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 89c9b00e63712..be131488161cd 100644 +index a266449065a0a..060c706e936ac 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); diff --git a/patches/6.9/0011-surface-shutdown.patch b/patches/6.9/0011-surface-shutdown.patch index 8402a487f0..924ed0343f 100644 --- a/patches/6.9/0011-surface-shutdown.patch +++ b/patches/6.9/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 9e0b83c9668c3d0e8e5ce9c254697056940a205d Mon Sep 17 00:00:00 2001 +From bc69ab6e0c225a8a0dd04954209e8964ba503aba Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -81,7 +81,7 @@ index eff7f5df08e27..d1cb4ff3ebc57 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 16493426a04ff..0eb821624056d 100644 +index 6f9c5ed5eb3ba..01ec9872f2bc4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -465,6 +465,7 @@ struct pci_dev { diff --git a/patches/6.9/0012-surface-gpe.patch b/patches/6.9/0012-surface-gpe.patch index b18860eba5..110c76bdcf 100644 --- a/patches/6.9/0012-surface-gpe.patch +++ b/patches/6.9/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 739ab84095d8ea8ec8fe05447706c6eb2ffa3f35 Mon Sep 17 00:00:00 2001 +From 90187974bb6b39b1e1d9f5994ca0e9aa20afcdc1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.9/0013-cameras.patch b/patches/6.9/0013-cameras.patch index 43894c83c7..9496aabfa5 100644 --- a/patches/6.9/0013-cameras.patch +++ b/patches/6.9/0013-cameras.patch @@ -1,4 +1,4 @@ -From 44ed44fe421e484bcf2de223d7e8077302635772 Mon Sep 17 00:00:00 2001 +From d85d16f63830263b7caf834e7db5b96d8a21aa8b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index d1464324de951..5d865a34dd9db 100644 -- 2.45.1 -From d9d5afcea9880a957d6a8d975a122b4f54ec28c2 Mon Sep 17 00:00:00 2001 +From 2b0dd055ffb8c8451001e4c31f15ee6eaf24f248 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 61bc54299a591..a61af0f4e9fce 100644 -- 2.45.1 -From bbf2fb14fae6c6bda12e156ff9d027913ab7860f Mon Sep 17 00:00:00 2001 +From d0eb04ab5c9153e24c51bf6b1d36708a5759e159 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 1e107fd49f828..e3e1696e7f0ee 100644 -- 2.45.1 -From bc2732708fc2a71f7fe3808aa84cc6eabbdd1285 Mon Sep 17 00:00:00 2001 +From 0cc59a0457b1b96281c4bccfda755207990acf7d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -276,7 +276,7 @@ index 07b302e093407..1d3097bc7e487 100644 -- 2.45.1 -From 0180b848e145642574d2a91175f92050dcec1ec7 Mon Sep 17 00:00:00 2001 +From 089a7447da1b70a9eacf239de12f905d47dc1cfa Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -315,7 +315,7 @@ index 30f61e04ecaf5..9c1292ca85522 100644 -- 2.45.1 -From 67553f37af4ea73f824108a08666b537c68972e5 Mon Sep 17 00:00:00 2001 +From 47f4104dddf43bf9a3197a569c7e132559a6d2ce Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -334,10 +334,10 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index 3ec323bd528b1..b55570a0142cb 100644 +index 4bb073587817c..cbcbf91db640a 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c -@@ -796,6 +796,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) +@@ -792,6 +792,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) INIT_LIST_HEAD(&sd->asc_list); @@ -366,7 +366,7 @@ index 89c7192148dfb..44eca113e7727 100644 -- 2.45.1 -From 82dff76b0fc0e6d8fec20339edcb52fcb3eb1fac Mon Sep 17 00:00:00 2001 +From 9bd6a3b0aede46de717f298aa509e31d7d3292d0 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -407,7 +407,7 @@ index e3e1696e7f0ee..423dc555093f7 100644 -- 2.45.1 -From ac5b449b3e7da53dfff6ab59dc32d9714eb2f106 Mon Sep 17 00:00:00 2001 +From a3703d67b8802d244efc734c7525ec568ea5e907 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -448,7 +448,7 @@ index 7807fa329db00..2d2abb25b944f 100644 -- 2.45.1 -From 3bdaa0c3e0b7dfa3b441e7d19d3f08ff3708e354 Mon Sep 17 00:00:00 2001 +From 4cd08afc49d50db17fa7c4f58a3a341159d71c26 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -699,7 +699,7 @@ index 0000000000000..35aeb5db89c8f -- 2.45.1 -From 05501de0dab9bc531918dcf2b8aa7e679760fd7b Mon Sep 17 00:00:00 2001 +From 0dfd0e9d881e7f2fa8fde4eca34d8c235612321e Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -746,7 +746,7 @@ index 3df58eb3e8822..81aff2d5d8988 100644 -- 2.45.1 -From c85328d7df3de31a574e42f66192c6a944f48bde Mon Sep 17 00:00:00 2001 +From c4e3d2d301a489fda30c6079d3f0e5fd93057f3a Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.9/0014-amd-gpio.patch b/patches/6.9/0014-amd-gpio.patch index e9d8371b0a..fae0741ea2 100644 --- a/patches/6.9/0014-amd-gpio.patch +++ b/patches/6.9/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From e0b584d3054d7c69d2e1b4f2ca54e42b79ee5446 Mon Sep 17 00:00:00 2001 +From d8b96395fa7bf340be82eafb6c93e34d809d2e3a Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 4bf82dbd2a6b5..7a8cb090c6568 100644 -- 2.45.1 -From dafa7b45eecb1e02dc857158566d2fb3087fa71f Mon Sep 17 00:00:00 2001 +From db60b087f5f21504f65ea41d67ded72538e0f5ea Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.9/0015-rtc.patch b/patches/6.9/0015-rtc.patch index 45ac63b8e3..e23cf5e0cd 100644 --- a/patches/6.9/0015-rtc.patch +++ b/patches/6.9/0015-rtc.patch @@ -1,4 +1,4 @@ -From e3e62473f885786f1b57421f5fed86ac5ba402ac Mon Sep 17 00:00:00 2001 +From 577071626f93a9e3f973351810fdb0082e9c00e9 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From bd9a34fa5bc95c14ff0a14d7b13527d818766153 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:19:38 +0200 Subject: [PATCH 020/236] pkg/debian: Add patch to link sign-file statically Since we build a single kernel package for Ubuntu and Debian, it often has a different compiler and libraries. Among other things, this leads to errors when building and signing external kernel modules via DKMS. In particular, https://github.com/linux-surface/kernel/issues/134. Try to fix this by linking the sign-file binary statically, as suggested by @quo. Signed-off-by: Maximilian Luz --- ...001-kbuild-Link-sign-file-statically.patch | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch new file mode 100644 index 0000000000..c58918dc6d --- /dev/null +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -0,0 +1,25 @@ +From 4113f0e722d93a3728d18464a88d752939e37d9d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 30 Jun 2024 17:10:28 +0200 +Subject: [PATCH] kbuild: Link sign-file statically + +--- + scripts/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/Makefile b/scripts/Makefile +index bc90520a54266..1d092bfd28e3a 100644 +--- a/scripts/Makefile ++++ b/scripts/Makefile +@@ -29,7 +29,7 @@ HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include + HOSTLDLIBS_sorttable = -lpthread + HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include + HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) +-HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) ++HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto) -Wl,-Bdynamic + + ifdef CONFIG_UNWINDER_ORC + ifeq ($(ARCH),x86_64) +-- +2.45.1 + From 79fca5a9f2056817d4e7b3bd5fb622900ded7bbe Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:23:50 +0200 Subject: [PATCH 021/236] Update Arch kernel to v6.9.7 --- pkg/arch/kernel/PKGBUILD | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 95237098f8..4d76b7678e 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,8 +3,8 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.9.3.arch1 -pkgrel=2 +pkgver=6.9.7.arch1 +pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('a8004dc1982bc7a1e86b7c07918868b48e5eeb746e520d06ce9b1d1356899527' +sha256sums=('e827ae94b1102cb1d752e101584e146de6e8f2b58eb75942fb9d8431b267d255' '3acffee6493e810bd13f042b0a8e97e2b66a977b8ae7ec7c25a604446271860f' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' - 'd9a981e75adba8f9762555493293e1d162fbe4c6468e734712941852c33a62aa' - '339131528b4075742c4c4d12fbe68f37be775d1f410fd622c6659f3877c1131d' - 'ae82fe11bee1a5aa83d31027f30fa9bfcef072e44a6f0cd2ad04c48646a9e94c' - 'dcf4996a7dd66b1bbc8be3df2ecc1e07586d3f44d41afea1570c12e6a3aa19fb' - '0cd3723970b31418ad8bbe5602bbc22a22e4b7075bec9dab1a32824a3041dba5' - 'a3b41f7aef025d890bd5f067aaf614f2c9b34ae8c50f2a8917b36a2d0883aa7b' - '34f49ba50c93fa4f9991e336fcc56bb8fc604ccf7296c00ddd24ed548b74ad4a' - '35007d1c88b3533e1dd3e67f74e6818bcd4f3a4d1e91938d895f5f12f6ff1471' - '343194f511cd42c7eb03149713587878aa5bfdcc9f53d67b5461e0127c411b8a' - 'aa3cc2dbcef667905b9a03239667afbee18d89747fcca309a8742b493ca69297' - 'a131f277f5e66943d199123e101206b8c29e76dbf2c37eda2d280410901d8ec2' - '973c6eb3bf8a147455f57ccff99e16ba2c64a92ca82d50ba3f12d6217cc29532' - 'fadeb2b97f78a4a6dabd82fb74f55e5087d9b2bcdb4b7cf37df4a27f5f5b6e52' - '551be5c8b7d78a061033fd7c414de9bdd35a24f0564630c77e29378b55894379' - 'e37e84960295a8713966d38734025f8f39395dcb9617c9c202493df05eccdec3' - 'bc5c4dd8b0fbe42fdb4ed336b827d4ee27c9ce7b2f216378e3305a4aed755a85') + '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' + 'faa0347daf092b96cff43393f5b954189bb12e5582dfd949884ba23b5e9b2b5c' + '99527819e246916757bba580c9380529ab8ea231e7e3e93a2183f2e50feb4969' + '9d6c28c1f6227c2896d372bda724054231f1be5f798b97844996c76a12a908ac' + '3644d22395d544192d23594dff39377cddb891a122330cb8366f41690492b857' + '23a71c37f0ed26f9fd27a54217472738f998287edbafc423a81faf99cb3c8c61' + '97002925baeff81101c76711c29025c5efa2d743ae8cff1da4f69b46024b985d' + 'be8da43c1ddb25ba2eec9c129a07c4b5de19c04087f4d9e3b857919c78d3545a' + '2f1471d40475a724b4bb024f8d783f4ca1cce7c0f5c78a68de9eeda9543f3f32' + '6275359c380b89a9f131bd1a9ba6cfe5ee283e37ff07d350d43f7cf9a26da5f2' + '160d801d699e9f2322525970f63afe8170df1a3f045567da81a35d443d1521ef' + '7915d257d1ab92d182646f1fbb3942d9e9c3276195f748ef3f958fe15120a16b' + 'db197da01e5e0ba8682d10c16ebda8d738c4b9ef1277c874a12d22abb181bc50' + '94bbec8146debbfdc7d781742fb4f7b0b657c43d27b731c87599ceabbc471b28' + 'afb5ef163a7c57c9eb07e2c4b73da09097dedcf3d6636de06d10c7999664e1a1' + 'f061046501917285950f915c9f7c6e124cdbae3b106b2416e2c868d1e79a5898') export KBUILD_BUILD_HOST=archlinux From 1c63d0f0ebedcfdbf1972d3d5f06efb767ee30d8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:26:35 +0200 Subject: [PATCH 022/236] Update Debian kernel to v6.9.7 --- pkg/debian/kernel/version.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index e43b4fc009..2b51fec02d 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.9.3" -KERNEL_REVISION="2" +KERNEL_VERSION="6.9.7" +KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 5d7787613819ec2d0ab950216a215945994aa829 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:28:24 +0200 Subject: [PATCH 023/236] Update Fedora kernels to v6.9.7 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index b16cc967fc..2c181b33f9 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.8.8-0" +PACKAGE_TAG = "kernel-6.9.7-0" ## ## The release number of the modified kernel package. From 469611e0e46cde62695e7c1c528d102fafca732d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 18:43:37 +0200 Subject: [PATCH 024/236] pkg/fedora: Remove filter-modules.sh override --- .../patches/0005-filter-modules.patch | 37 +++++++++---------- .../kernel-surface/patches/0006-ipu3-fw.patch | 25 ------------- 2 files changed, 18 insertions(+), 44 deletions(-) delete mode 100644 pkg/fedora/kernel-surface/patches/0006-ipu3-fw.patch diff --git a/pkg/fedora/kernel-surface/patches/0005-filter-modules.patch b/pkg/fedora/kernel-surface/patches/0005-filter-modules.patch index 82bcfbbd72..d497856260 100644 --- a/pkg/fedora/kernel-surface/patches/0005-filter-modules.patch +++ b/pkg/fedora/kernel-surface/patches/0005-filter-modules.patch @@ -1,26 +1,25 @@ -From bb654591f82503f9e3c319902af2a2b64c18ae50 Mon Sep 17 00:00:00 2001 +From a82af933b2ee35e24140ee7fddf9a083596cda3f Mon Sep 17 00:00:00 2001 From: Dorian Stoll -Date: Sat, 13 Jan 2024 12:30:02 +0100 -Subject: [PATCH] HACK: Move surface_fan and surface_temp to kernel-modules +Date: Mon, 29 Jan 2024 19:26:41 +0100 +Subject: [PATCH] Pull in intel-vsc-firmware +This package contains the IPU3 firmware needed for camera support. --- - redhat/fedora_files/filter-modules.sh.fedora | 3 +++ - 1 file changed, 3 insertions(+) + redhat/kernel.spec.template | 1 + + 1 file changed, 1 insertion(+) -diff --git a/redhat/fedora_files/filter-modules.sh.fedora b/redhat/fedora_files/filter-modules.sh.fedora -index 2e7b79eba1d9..7ef7614cbda2 100755 ---- a/redhat/fedora_files/filter-modules.sh.fedora -+++ b/redhat/fedora_files/filter-modules.sh.fedora -@@ -84,6 +84,9 @@ filter_ko() { - return 0 - } - -+# HACK: move surface_fan and surface_temp to kernel-modules -+singlemods="${singlemods} surface_fan surface_temp" -+ - # Filter the drivers/ subsystems - for subsys in ${driverdirs} - do +diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template +index 4ece0fa3a56c..768316b2ec82 100644 +--- a/redhat/kernel.spec.template ++++ b/redhat/kernel.spec.template +@@ -1028,6 +1028,7 @@ Requires(pre): %{kernel_prereq}\ + Requires(pre): %{initrd_prereq}\ + Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ + Recommends: linux-firmware\ ++Recommends: intel-vsc-firmware\ + Recommends: iptsd\ + Recommends: %{package_name}-default-watchdog\ + Requires(preun): systemd >= 200\ -- 2.43.0 diff --git a/pkg/fedora/kernel-surface/patches/0006-ipu3-fw.patch b/pkg/fedora/kernel-surface/patches/0006-ipu3-fw.patch deleted file mode 100644 index d497856260..0000000000 --- a/pkg/fedora/kernel-surface/patches/0006-ipu3-fw.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a82af933b2ee35e24140ee7fddf9a083596cda3f Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Mon, 29 Jan 2024 19:26:41 +0100 -Subject: [PATCH] Pull in intel-vsc-firmware - -This package contains the IPU3 firmware needed for camera support. ---- - redhat/kernel.spec.template | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 4ece0fa3a56c..768316b2ec82 100644 ---- a/redhat/kernel.spec.template -+++ b/redhat/kernel.spec.template -@@ -1028,6 +1028,7 @@ Requires(pre): %{kernel_prereq}\ - Requires(pre): %{initrd_prereq}\ - Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ - Recommends: linux-firmware\ -+Recommends: intel-vsc-firmware\ - Recommends: iptsd\ - Recommends: %{package_name}-default-watchdog\ - Requires(preun): systemd >= 200\ --- -2.43.0 - From b9167d390658eafb1c8f3bcf9b8275d3937ab41e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 19:37:15 +0200 Subject: [PATCH 025/236] pkg/fedora: Update packaging patches --- .../kernel-surface/patches/0001-iptsd.patch | 10 +++--- .../patches/0002-provides.patch | 18 +++++----- .../patches/0003-obsoletes.patch | 26 +++++++------- .../patches/0004-default-kernel.patch | 20 +++++------ ...ilter-modules.patch => 0005-ipu3-fw.patch} | 10 +++--- .../secureboot/0001-secureboot.patch | 36 +++++++------------ 6 files changed, 54 insertions(+), 66 deletions(-) rename pkg/fedora/kernel-surface/patches/{0005-filter-modules.patch => 0005-ipu3-fw.patch} (75%) diff --git a/pkg/fedora/kernel-surface/patches/0001-iptsd.patch b/pkg/fedora/kernel-surface/patches/0001-iptsd.patch index d35cffa88c..3a9fc4c64e 100644 --- a/pkg/fedora/kernel-surface/patches/0001-iptsd.patch +++ b/pkg/fedora/kernel-surface/patches/0001-iptsd.patch @@ -1,7 +1,7 @@ -From 1cad947df5f2ec874863e42cce595a76dad64cc2 Mon Sep 17 00:00:00 2001 +From bd92f2ec163acc3a109e2fd34793553e4038b4d6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:33:03 +0200 -Subject: [PATCH] Pull in iptsd as a weak dependency +Subject: [PATCH 1/5] Pull in iptsd as a weak dependency Signed-off-by: Dorian Stoll --- @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index d3dafe56aa64..24823cd8b784 100644 +index c987db5886f2..1dbc56b1be3b 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1052,6 +1052,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1001,6 +1001,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index d3dafe56aa64..24823cd8b784 100644 Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -- -2.41.0 +2.45.1 diff --git a/pkg/fedora/kernel-surface/patches/0002-provides.patch b/pkg/fedora/kernel-surface/patches/0002-provides.patch index 1f032adfc7..58181abc20 100644 --- a/pkg/fedora/kernel-surface/patches/0002-provides.patch +++ b/pkg/fedora/kernel-surface/patches/0002-provides.patch @@ -1,7 +1,7 @@ -From 17907fed744ae17414a1ad8bebc335e12dac7691 Mon Sep 17 00:00:00 2001 +From 6e967041622e39df2ce421e8dcdc4aed67e8348d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:34:38 +0200 -Subject: [PATCH] Let kernel-surface provide the standard package names +Subject: [PATCH 2/5] Let kernel-surface provide the standard package names Signed-off-by: Dorian Stoll --- @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 5 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 24823cd8b784..ea7de5884a89 100644 +index 1dbc56b1be3b..98995c878ea8 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -697,6 +697,7 @@ Requires: kernel-core-uname-r = %{KVERREL} +@@ -653,6 +653,7 @@ Requires: kernel-core-uname-r = %{KVERREL} Requires: kernel-modules-uname-r = %{KVERREL} Requires: kernel-modules-core-uname-r = %{KVERREL} Provides: installonlypkg(kernel) @@ -20,7 +20,7 @@ index 24823cd8b784..ea7de5884a89 100644 %endif -@@ -1352,6 +1353,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} +@@ -1333,6 +1334,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} Provides: kernel%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release}\ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1:+%{1}}}\ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -28,7 +28,7 @@ index 24823cd8b784..ea7de5884a89 100644 Provides: installonlypkg(kernel)\ AutoReqProv: no\ Requires(pre): findutils\ -@@ -1381,6 +1383,7 @@ against the %{?2:%{2} }kernel package.\ +@@ -1362,6 +1364,7 @@ against the %{?2:%{2} }kernel package.\ Summary: Meta package to install matching core and devel packages for a given %{?2:%{2} }kernel\ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ @@ -36,7 +36,7 @@ index 24823cd8b784..ea7de5884a89 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1502,6 +1505,7 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}+%{uname_suffix %{1}}\ +@@ -1483,6 +1486,7 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ Requires: realtime-setup\ %endif\ Provides: installonlypkg(kernel)\ @@ -44,7 +44,7 @@ index 24823cd8b784..ea7de5884a89 100644 %description %{1}\ The meta-package for the %{1} kernel\ %{nil} -@@ -1534,6 +1538,7 @@ This package provides KVM modules for package kernel%{?1:-%{1}}.\ +@@ -1516,6 +1520,7 @@ This package provides KVM modules for package kernel%{?1:-%{1}}.\ Summary: %{variant_summary}\ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: installonlypkg(kernel)\ @@ -53,5 +53,5 @@ index 24823cd8b784..ea7de5884a89 100644 Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ -- -2.41.0 +2.45.1 diff --git a/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch b/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch index 2146a7b37f..66048ce330 100644 --- a/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch +++ b/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch @@ -1,7 +1,7 @@ -From 819c1b06089925d6944bf2dad9dc29649b7510d5 Mon Sep 17 00:00:00 2001 +From 1ff16b22002a0c7f76f74042e07d8c44d2fe3db7 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:40:32 +0200 -Subject: [PATCH] Let kernel-surface conflict with older versions of the +Subject: [PATCH 3/5] Let kernel-surface conflict with older versions of the package Signed-off-by: Dorian Stoll @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 20 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index ea7de5884a89..43dce82a9d36 100644 +index 98995c878ea8..4f3253f17121 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -698,6 +698,10 @@ Requires: kernel-modules-uname-r = %{KVERREL} +@@ -654,6 +654,10 @@ Requires: kernel-modules-uname-r = %{KVERREL} Requires: kernel-modules-core-uname-r = %{KVERREL} Provides: installonlypkg(kernel) Provides: kernel = %{KVERREL} @@ -24,7 +24,7 @@ index ea7de5884a89..43dce82a9d36 100644 %endif -@@ -1355,6 +1359,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff +@@ -1336,6 +1340,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: kernel-devel = %{KVERREL}%{?1:+%{1}}\ Provides: installonlypkg(kernel)\ @@ -33,7 +33,7 @@ index ea7de5884a89..43dce82a9d36 100644 AutoReqProv: no\ Requires(pre): findutils\ Requires: findutils\ -@@ -1384,6 +1390,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ +@@ -1365,6 +1371,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ Provides: kernel-devel-matched = %{specrpmversion}-%{release}\ @@ -42,7 +42,7 @@ index ea7de5884a89..43dce82a9d36 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1416,6 +1424,8 @@ Provides: kernel%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix +@@ -1397,6 +1405,8 @@ Provides: kernel%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -51,7 +51,7 @@ index ea7de5884a89..43dce82a9d36 100644 AutoReq: no\ AutoProv: yes\ %description %{?1:%{1}-}modules-internal\ -@@ -1437,6 +1447,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? +@@ -1418,6 +1428,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -60,7 +60,7 @@ index ea7de5884a89..43dce82a9d36 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-extra-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1460,6 +1472,8 @@ Provides: installonlypkg(kernel-module)\ +@@ -1441,6 +1453,8 @@ Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -69,7 +69,7 @@ index ea7de5884a89..43dce82a9d36 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1482,6 +1496,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: +@@ -1463,6 +1477,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -78,7 +78,7 @@ index ea7de5884a89..43dce82a9d36 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1504,6 +1520,8 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}+%{uname_suffix %{1}}\ +@@ -1485,6 +1501,8 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ %if "%{1}" == "rt" || "%{1}" == "rt-debug"\ Requires: realtime-setup\ %endif\ @@ -87,7 +87,7 @@ index ea7de5884a89..43dce82a9d36 100644 Provides: installonlypkg(kernel)\ Provides: kernel = %{KVERREL}+%{1}\ %description %{1}\ -@@ -1539,6 +1557,8 @@ Summary: %{variant_summary}\ +@@ -1521,6 +1539,8 @@ Summary: %{variant_summary}\ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: installonlypkg(kernel)\ Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{?1:+%{1}}\ @@ -97,5 +97,5 @@ index ea7de5884a89..43dce82a9d36 100644 Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ -- -2.41.0 +2.45.1 diff --git a/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch b/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch index 7b273304ef..52c8bc6306 100644 --- a/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch +++ b/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch @@ -1,7 +1,7 @@ -From 81141a454f41cbc5fd41b778f85b10552c8676e8 Mon Sep 17 00:00:00 2001 +From 64bb7e9daea6e836c3eb8334368ea9cd651ce8db Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:41:11 +0200 -Subject: [PATCH] Install scripts and service files for keeping the surface +Subject: [PATCH 4/5] Install scripts and service files for keeping the surface kernel the default Signed-off-by: Dorian Stoll @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 34 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 43dce82a9d36..28df94e561d4 100644 +index 4f3253f17121..3ce7fbec4beb 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1025,6 +1025,11 @@ Source4000: README.rst +@@ -974,6 +974,11 @@ Source4000: README.rst Source4001: rpminspect.yaml Source4002: gating.yaml @@ -25,7 +25,7 @@ index 43dce82a9d36..28df94e561d4 100644 ## Patches needed for building this package %if !%{nopatches} -@@ -1058,6 +1063,7 @@ Requires(pre): %{initrd_prereq}\ +@@ -1007,6 +1012,7 @@ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ Recommends: iptsd\ @@ -33,7 +33,7 @@ index 43dce82a9d36..28df94e561d4 100644 Requires(preun): systemd >= 200\ Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -@@ -1072,6 +1078,14 @@ AutoProv: yes\ +@@ -1021,6 +1027,14 @@ AutoProv: yes\ %{nil} @@ -48,7 +48,7 @@ index 43dce82a9d36..28df94e561d4 100644 %package doc Summary: Various documentation bits found in the kernel source Group: Documentation -@@ -2945,6 +2959,11 @@ find Documentation -type d | xargs chmod u+w +@@ -3091,6 +3105,11 @@ find Documentation -type d | xargs chmod u+w cd linux-%{KVERREL} @@ -60,7 +60,7 @@ index 43dce82a9d36..28df94e561d4 100644 %if %{with_doc} docdir=$RPM_BUILD_ROOT%{_datadir}/doc/kernel-doc-%{specversion}-%{pkgrelease} -@@ -3197,6 +3216,15 @@ popd +@@ -3347,6 +3366,15 @@ popd ### scripts ### @@ -76,7 +76,7 @@ index 43dce82a9d36..28df94e561d4 100644 %if %{with_tools} %post -n %{package_name}-tools-libs /sbin/ldconfig -@@ -3609,6 +3637,12 @@ fi\ +@@ -3810,6 +3838,12 @@ fi\ %{_libexecdir}/kselftests %endif @@ -90,5 +90,5 @@ index 43dce82a9d36..28df94e561d4 100644 %if %{with_up_base} %ifnarch %nobuildarches noarch -- -2.41.0 +2.45.1 diff --git a/pkg/fedora/kernel-surface/patches/0005-filter-modules.patch b/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch similarity index 75% rename from pkg/fedora/kernel-surface/patches/0005-filter-modules.patch rename to pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch index d497856260..fe7a70bec2 100644 --- a/pkg/fedora/kernel-surface/patches/0005-filter-modules.patch +++ b/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch @@ -1,7 +1,7 @@ -From a82af933b2ee35e24140ee7fddf9a083596cda3f Mon Sep 17 00:00:00 2001 +From 076cb99d65797ebc56a798976dc1b043ff58687a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Mon, 29 Jan 2024 19:26:41 +0100 -Subject: [PATCH] Pull in intel-vsc-firmware +Subject: [PATCH 5/5] Pull in intel-vsc-firmware This package contains the IPU3 firmware needed for camera support. --- @@ -9,10 +9,10 @@ This package contains the IPU3 firmware needed for camera support. 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 4ece0fa3a56c..768316b2ec82 100644 +index 3ce7fbec4beb..e6bece22b1f3 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1028,6 +1028,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1011,6 +1011,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index 4ece0fa3a56c..768316b2ec82 100644 Recommends: %{package_name}-default-watchdog\ Requires(preun): systemd >= 200\ -- -2.43.0 +2.45.1 diff --git a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch index 80dc88ebe2..ccf22c40f3 100644 --- a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch +++ b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch @@ -1,18 +1,18 @@ -From d4bbfbfee98f8b117885cf88a48f686ac889d73e Mon Sep 17 00:00:00 2001 +From 9fe406af6d54768c681817a91cf28e6159725c05 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:45:33 +0200 Subject: [PATCH] Use a custom key and certificate for Secure Boot signing Signed-off-by: Dorian Stoll --- - redhat/kernel.spec.template | 15 +++++++++------ - 1 file changed, 9 insertions(+), 6 deletions(-) + redhat/kernel.spec.template | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 0fb19cc23041..d7bd6013423c 100644 +index e6bece22b1f3..c5995edff65b 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -762,6 +762,7 @@ BuildRequires: system-sb-certs +@@ -764,6 +764,7 @@ BuildRequires: system-sb-certs %ifarch x86_64 aarch64 BuildRequires: nss-tools BuildRequires: pesign >= 0.10-4 @@ -20,7 +20,7 @@ index 0fb19cc23041..d7bd6013423c 100644 %endif %endif %endif -@@ -821,6 +822,13 @@ Source2: kernel.changelog +@@ -827,6 +828,13 @@ Source13: redhatsecureboot501.cer %define signing_key_filename kernel-signing-s390.cer %endif @@ -31,30 +31,18 @@ index 0fb19cc23041..d7bd6013423c 100644 + +%endif + - %if %{?released_kernel} - - Source10: redhatsecurebootca5.cer -@@ -2201,9 +2209,7 @@ BuildKernel() { + # Fedora/ELN pesign macro expects to see these cert file names, see: + # https://github.com/rhboot/pesign/blob/main/src/pesign-rpmbuild-helper.in#L216 + %if 0%{?fedora}%{?eln} +@@ -2188,7 +2196,7 @@ BuildKernel() { %ifarch x86_64 aarch64 %{log_msg "Sign kernel image"} -- %pesign -s -i $SignImage -o vmlinuz.tmp -a %{secureboot_ca_0} -c %{secureboot_key_0} -n %{pesign_name_0} -- %pesign -s -i vmlinuz.tmp -o vmlinuz.signed -a %{secureboot_ca_1} -c %{secureboot_key_1} -n %{pesign_name_1} -- rm vmlinuz.tmp +- %pesign -s -i $SignImage -o vmlinuz.signed -a %{secureboot_ca_0} -c %{secureboot_key_0} -n %{pesign_name_0} + sbsign --key %{SOURCE7001} --cert %{SOURCE7002} --output vmlinuz.signed $SignImage %endif %ifarch s390x ppc64le if [ -x /usr/bin/rpm-sign ]; then -@@ -2783,9 +2789,6 @@ BuildKernel() { - %{log_msg "Install certs"} - mkdir -p $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer - %ifarch x86_64 aarch64 -- install -m 0644 %{secureboot_ca_0} $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer/kernel-signing-ca-20200609.cer -- install -m 0644 %{secureboot_ca_1} $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer/kernel-signing-ca-20140212.cer -- ln -s kernel-signing-ca-20200609.cer $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer/kernel-signing-ca.cer - %else - install -m 0644 %{secureboot_ca_0} $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer/kernel-signing-ca.cer - %endif -- -2.44.0 +2.45.1 From 850985565b7aecfdbbbbcc8b0ab0bef5448f5888 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 20:38:59 +0200 Subject: [PATCH 026/236] pkg/fedora: Fix config inconsistencies --- .../kernel-surface/configs/fedora.config | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/pkg/fedora/kernel-surface/configs/fedora.config b/pkg/fedora/kernel-surface/configs/fedora.config index 8ab727953a..2a304dc5b9 100644 --- a/pkg/fedora/kernel-surface/configs/fedora.config +++ b/pkg/fedora/kernel-surface/configs/fedora.config @@ -12,3 +12,70 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y ## Disable (wrong) NX compatibility flag. ## # CONFIG_EFI_DXE_MEM_ATTRIBUTES is not set + +## +## UFS pulls in DEVFREQ and NLS modules. Fedora's packaging system complains +## and aborts if any options aren't specified, so specify them explicitly here. +## +CONFIG_DEVFREQ_THERMAL=y +CONFIG_SCSI_UFS_BSG=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_FAULT_INJECTION=n +# CONFIG_SCSI_UFS_DWC_TC_PCI is not set +# CONFIG_SCSI_UFS_TI_J721E is not set +CONFIG_SCSI_UFSHCD_PLATFORM=m +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m +CONFIG_DEVFREQ_GOV_PERFORMANCE=m +CONFIG_DEVFREQ_GOV_POWERSAVE=m +CONFIG_DEVFREQ_GOV_USERSPACE=m +CONFIG_DEVFREQ_GOV_PASSIVE=m +CONFIG_PM_DEVFREQ=y +CONFIG_PM_DEVFREQ_EVENT=y +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_737=y +CONFIG_NLS_CODEPAGE_775=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_CODEPAGE_852=y +CONFIG_NLS_CODEPAGE_855=y +CONFIG_NLS_CODEPAGE_857=y +CONFIG_NLS_CODEPAGE_860=y +CONFIG_NLS_CODEPAGE_861=y +CONFIG_NLS_CODEPAGE_862=y +CONFIG_NLS_CODEPAGE_863=y +CONFIG_NLS_CODEPAGE_864=y +CONFIG_NLS_CODEPAGE_865=y +CONFIG_NLS_CODEPAGE_866=y +CONFIG_NLS_CODEPAGE_869=y +CONFIG_NLS_CODEPAGE_936=y +CONFIG_NLS_CODEPAGE_950=y +CONFIG_NLS_CODEPAGE_932=y +CONFIG_NLS_CODEPAGE_949=y +CONFIG_NLS_CODEPAGE_874=y +CONFIG_NLS_ISO8859_8=y +CONFIG_NLS_CODEPAGE_1250=y +CONFIG_NLS_CODEPAGE_1251=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=y +CONFIG_NLS_ISO8859_3=y +CONFIG_NLS_ISO8859_4=y +CONFIG_NLS_ISO8859_5=y +CONFIG_NLS_ISO8859_6=y +CONFIG_NLS_ISO8859_7=y +CONFIG_NLS_ISO8859_9=y +CONFIG_NLS_ISO8859_13=y +CONFIG_NLS_ISO8859_14=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_KOI8_R=y +CONFIG_NLS_KOI8_U=y +CONFIG_NLS_MAC_ROMAN=y +CONFIG_NLS_MAC_CELTIC=y +CONFIG_NLS_MAC_CENTEURO=y +CONFIG_NLS_MAC_CROATIAN=y +CONFIG_NLS_MAC_CYRILLIC=y +CONFIG_NLS_MAC_GAELIC=y +CONFIG_NLS_MAC_GREEK=y +CONFIG_NLS_MAC_ICELAND=y +CONFIG_NLS_MAC_INUIT=y +CONFIG_NLS_MAC_ROMANIAN=y +CONFIG_NLS_MAC_TURKISH=y +CONFIG_NLS_UTF8=y From dbc445a23d3b546447eab6d46b49ed76af544070 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 22:21:53 +0200 Subject: [PATCH 027/236] pkg/fedora: Fix config inconsistencies Try number 2. --- pkg/fedora/kernel-surface/configs/fedora.config | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/fedora/kernel-surface/configs/fedora.config b/pkg/fedora/kernel-surface/configs/fedora.config index 2a304dc5b9..f71a583746 100644 --- a/pkg/fedora/kernel-surface/configs/fedora.config +++ b/pkg/fedora/kernel-surface/configs/fedora.config @@ -20,15 +20,20 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_DEVFREQ_THERMAL=y CONFIG_SCSI_UFS_BSG=y CONFIG_SCSI_UFS_CRYPTO=y -CONFIG_SCSI_UFS_FAULT_INJECTION=n +# CONFIG_SCSI_UFS_FAULT_INJECTION is not set # CONFIG_SCSI_UFS_DWC_TC_PCI is not set # CONFIG_SCSI_UFS_TI_J721E is not set +# CONFIG_SCSI_UFS_CDNS_PLATFORM is not set +# CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set +# CONFIG_SCSI_UFS_QCOM is not set +# CONFIG_SCSI_UFS_HISI is not set +CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=m -CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m -CONFIG_DEVFREQ_GOV_PERFORMANCE=m -CONFIG_DEVFREQ_GOV_POWERSAVE=m -CONFIG_DEVFREQ_GOV_USERSPACE=m -CONFIG_DEVFREQ_GOV_PASSIVE=m +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_PM_DEVFREQ=y CONFIG_PM_DEVFREQ_EVENT=y CONFIG_NLS=y From 358fbae31595bb0068b778af6b4f90bd9b1c5d30 Mon Sep 17 00:00:00 2001 From: theo Date: Wed, 17 Jul 2024 17:46:59 +0200 Subject: [PATCH 028/236] update thermald SL4a readme replace backslashes (\) with forward-slashes (/) for thermald config path --- contrib/thermald/surface_laptop_4a/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/thermald/surface_laptop_4a/README.md b/contrib/thermald/surface_laptop_4a/README.md index 7fc9e99653..d9734fd5dd 100644 --- a/contrib/thermald/surface_laptop_4a/README.md +++ b/contrib/thermald/surface_laptop_4a/README.md @@ -30,7 +30,7 @@ sudo systemctl stop thermald.service Place thermal-conf.xml into the following directory: ``` -\etc\thermald\ +/etc/thermald/ ``` Restart thermald: From ae76c55bd6850b034eddde9d72d076f16005fd3d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 18 Jul 2024 22:46:59 +0200 Subject: [PATCH 029/236] Update v6.9 patches Changes: - Add basic SAM support for the Surface Pro 10 - Rebase onto v6.9.10 Links: - kernel: https://github.com/linux-surface/kernel/commit/78af53e2f1d92ee15a4dc5f289c0a85684cccb07 --- patches/6.9/0001-secureboot.patch | 2 +- patches/6.9/0002-surface3-oemb.patch | 2 +- patches/6.9/0003-mwifiex.patch | 6 +- patches/6.9/0004-ath10k.patch | 2 +- patches/6.9/0005-ipts.patch | 8 +-- patches/6.9/0006-ithc.patch | 6 +- patches/6.9/0007-surface-sam.patch | 78 +++++++++++++++++---- patches/6.9/0008-surface-sam-over-hid.patch | 4 +- patches/6.9/0009-surface-button.patch | 4 +- patches/6.9/0010-surface-typecover.patch | 8 +-- patches/6.9/0011-surface-shutdown.patch | 2 +- patches/6.9/0012-surface-gpe.patch | 2 +- patches/6.9/0013-cameras.patch | 22 +++--- patches/6.9/0014-amd-gpio.patch | 4 +- patches/6.9/0015-rtc.patch | 2 +- 15 files changed, 103 insertions(+), 49 deletions(-) diff --git a/patches/6.9/0001-secureboot.patch b/patches/6.9/0001-secureboot.patch index 3f9fae137f..06f45fc2ee 100644 --- a/patches/6.9/0001-secureboot.patch +++ b/patches/6.9/0001-secureboot.patch @@ -1,4 +1,4 @@ -From def57db20e3390d77283c4715bf277c4b16073ff Mon Sep 17 00:00:00 2001 +From a4b96f72850f2e7259e12c3a4a9d59131078a49e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag diff --git a/patches/6.9/0002-surface3-oemb.patch b/patches/6.9/0002-surface3-oemb.patch index 07b88d1dc1..6f65d62542 100644 --- a/patches/6.9/0002-surface3-oemb.patch +++ b/patches/6.9/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 9517aa6b06c90854df9f7e4a8b633f4f2dedfe9b Mon Sep 17 00:00:00 2001 +From c70635debfb516e9fd4e6e1a627a184ef1a7ebf9 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.9/0003-mwifiex.patch b/patches/6.9/0003-mwifiex.patch index c52004110f..290e0bc02f 100644 --- a/patches/6.9/0003-mwifiex.patch +++ b/patches/6.9/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From c4550d9917b83ef96aacf4f7162797c1566fd4de Mon Sep 17 00:00:00 2001 +From 7a613d68d8ec81985333f0ccbd3c7e2515a8396c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5bf..5d30ae39d65ec 100644 -- 2.45.1 -From 0b8f67a82e0256c352d02f53156f7f278a5f5f9e Mon Sep 17 00:00:00 2001 +From 72063300ceaac5353d979ab3fb1c90431d49973d Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65ec..c14eb56eb9118 100644 -- 2.45.1 -From b5f2d2733bdf90dc863f63817280e77d5566aa34 Mon Sep 17 00:00:00 2001 +From ba70b3a57603beac9f007e173a7189ad12056a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.9/0004-ath10k.patch b/patches/6.9/0004-ath10k.patch index 7d1e817310..93f6a59d06 100644 --- a/patches/6.9/0004-ath10k.patch +++ b/patches/6.9/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 9f3a99c15c226a002ef10ca9f494d49397729290 Mon Sep 17 00:00:00 2001 +From 3d6d8efe56a7b9ad8cea6616c918f5c057ec97c6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.9/0005-ipts.patch b/patches/6.9/0005-ipts.patch index ab53870c35..e967801eea 100644 --- a/patches/6.9/0005-ipts.patch +++ b/patches/6.9/0005-ipts.patch @@ -1,4 +1,4 @@ -From 91720b1952e1ff5a54820c2a1653b78547394358 Mon Sep 17 00:00:00 2001 +From c2d6692b776f0d082e204f153ee9cca409e6aa1d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 6589635f8ba32..a1df48a434e2f 100644 -- 2.45.1 -From 89b8b2d10c6621b08e331bf3400f18be0c3b220e Mon Sep 17 00:00:00 2001 +From 070ffec42eb5b8e6c0403bbcaa86a6bd19323dea Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e4a03588a8a0f..61bc54299a591 100644 -- 2.45.1 -From c57990a8a2940d822267089e497ea71d87b8d91b Mon Sep 17 00:00:00 2001 +From 2e10f861a1556ad45bf1e4a7d5c81806653cdeb7 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3236,7 +3236,7 @@ index 0000000000000..1f966b8b32c45 -- 2.45.1 -From eec87febb5aedae2e6bcd20cb9539ea2aff4bcdb Mon Sep 17 00:00:00 2001 +From 1930dddc7cf94e188a3cf6e957b9bd8622ba4a6b Mon Sep 17 00:00:00 2001 From: Jasmin Huber Date: Mon, 15 Apr 2024 10:22:55 +0200 Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile diff --git a/patches/6.9/0006-ithc.patch b/patches/6.9/0006-ithc.patch index 3eb8993010..78307cadac 100644 --- a/patches/6.9/0006-ithc.patch +++ b/patches/6.9/0006-ithc.patch @@ -1,4 +1,4 @@ -From 9753b4d8abe343fb74f7305ea52dcb1839b70409 Mon Sep 17 00:00:00 2001 +From 28368e616f0710082f3c43e3614650b05a09773c Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 566297bc87ddb..a8cd8f12d5937 100644 -- 2.45.1 -From e58e432524ab069a1582b38632f9fed86754708a Mon Sep 17 00:00:00 2001 +From 07b04f9dbdee2152e14ac7777f71ee3a13dd019d Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -1818,7 +1818,7 @@ index 0000000000000..028e55a4ec53e -- 2.45.1 -From 822127904dec578540affeb80b26a46744333029 Mon Sep 17 00:00:00 2001 +From 949ce7e16eb91fb96b2495a002364a82ee543f16 Mon Sep 17 00:00:00 2001 From: quo Date: Fri, 19 Apr 2024 22:11:09 +0200 Subject: [PATCH] hid: ithc: Update from quo/ithc-linux diff --git a/patches/6.9/0007-surface-sam.patch b/patches/6.9/0007-surface-sam.patch index 83f892e5af..41e4665cef 100644 --- a/patches/6.9/0007-surface-sam.patch +++ b/patches/6.9/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 619f5f1754e755935ce38ea2ada145ba19dcff6a Mon Sep 17 00:00:00 2001 +From 4dd4e50694677d063eceb17e44b24fd0473df390 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 May 2024 16:15:49 +0200 Subject: [PATCH] serial: Clear UPF_DEAD before calling @@ -79,7 +79,7 @@ index c476d884356db..b47a277978a0b 100644 -- 2.45.1 -From 51695a151d5b9e7468911944a8357427228efc57 Mon Sep 17 00:00:00 2001 +From f467f4373c2620fbf27c1ce0246bad8437034e33 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 5 May 2024 21:07:50 +0800 Subject: [PATCH] platform/surface: aggregator: Log critical errors during SAM @@ -215,7 +215,7 @@ index ba550eaa06fcf..797d0645bd77f 100644 -- 2.45.1 -From f71471eace9cad92cd1c57d3bc214c6fc18190aa Mon Sep 17 00:00:00 2001 +From aa3d6b4b41566cbb68ba342463fee27924238b30 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 19 Apr 2024 20:41:47 +0200 Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is @@ -270,7 +270,7 @@ index 7fc602e01487d..7e89f547999b2 100644 -- 2.45.1 -From 84059069e8000f85666ec080258a5dc66a255e9d Mon Sep 17 00:00:00 2001 +From dd4678d91fa59cdf247be667fa64b8959029123d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Oct 2023 14:57:11 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -303,7 +303,7 @@ index 035d6b4105cd6..74688a2ed4b2e 100644 -- 2.45.1 -From 48129c8bacd2d53c44d08f2510bad0d23daef42e Mon Sep 17 00:00:00 2001 +From 3598d00445216e0b1b0b3e4141c5a2f359bf19c4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 19:47:00 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -373,7 +373,7 @@ index 74688a2ed4b2e..f02a933160ff2 100644 -- 2.45.1 -From 40519c80a360c0113c5e8f689b4c3d586613c162 Mon Sep 17 00:00:00 2001 +From eab61a4d3b4de4f3f61789748ecff660b07fbf8b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 20:05:57 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -430,7 +430,7 @@ index f02a933160ff2..34df1bdad83bd 100644 -- 2.45.1 -From b80d055e4865d17e11d17d53501409fa87555345 Mon Sep 17 00:00:00 2001 +From 1b6e5187d5961bd4bf4aa939426f0dfa9f01abd8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -658,7 +658,7 @@ index 0000000000000..48c3e826713f6 -- 2.45.1 -From 32fda2a1c96376a27be0e0c57755711fa662cd52 Mon Sep 17 00:00:00 2001 +From 5e8b9e18c1502bd5371a42014b104e91467a3437 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -853,7 +853,7 @@ index 48c3e826713f6..4c08926139dbf 100644 -- 2.45.1 -From c0169d071bb08ca5ef4551bbe166120f37047900 Mon Sep 17 00:00:00 2001 +From 1e3af9982108daf50b030c5672df1f2791107608 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:21:12 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -896,7 +896,7 @@ index 34df1bdad83bd..c0bf0cadcd258 100644 -- 2.45.1 -From 01e4b0bb9383af68d9396e20fb749b997a111de3 Mon Sep 17 00:00:00 2001 +From fe8e2664ddcf80418be9e2f4ae3b9211257b6647 Mon Sep 17 00:00:00 2001 From: Ivor Wanders Date: Sat, 16 Dec 2023 15:56:39 -0500 Subject: [PATCH] platform/surface: platform_profile: add fan profile switching @@ -1223,7 +1223,7 @@ index a5a3941b3f43a..e54d0a8f7daa5 100644 -- 2.45.1 -From 300366539fe3053b4bfaf9ce31d571c8a3bf0ac0 Mon Sep 17 00:00:00 2001 +From a36158d7724a8799dc53a8605f22d368d52d3bc5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:47:47 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -1252,7 +1252,7 @@ index 07a4c4e1120d3..4dc79f791d390 100644 -- 2.45.1 -From 2942f156e20ee4deead0441bfb665f22bb0e4a87 Mon Sep 17 00:00:00 2001 +From ed9d1558fb33c0654e51457081b231e24bab480e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:48:02 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -1281,3 +1281,57 @@ index 4dc79f791d390..77f903a04d128 100644 -- 2.45.1 +From 72c97a89faddb83b43940ae213db3d96bbd14210 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 28 Jun 2024 22:31:37 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Support for + Surface Pro 10 + +Patchset: surface-sam +--- + .../surface/surface_aggregator_registry.c | 22 +++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 77f903a04d128..7d01d989d2a49 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -377,6 +377,25 @@ static const struct software_node *ssam_node_group_sp9[] = { + NULL, + }; + ++/* Devices for Surface Pro 10 */ ++static const struct software_node *ssam_node_group_sp10[] = { ++ &ssam_node_root, ++ &ssam_node_hub_kip, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, ++ &ssam_node_pos_tablet_switch, ++ &ssam_node_hid_kip_keyboard, ++ &ssam_node_hid_kip_penstash, ++ &ssam_node_hid_kip_touchpad, ++ &ssam_node_hid_kip_fwupd, ++ &ssam_node_hid_sam_sensors, ++ &ssam_node_hid_sam_ucm_ucsi, ++ NULL, ++}; ++ + + /* -- SSAM platform/meta-hub driver. ---------------------------------------- */ + +@@ -399,6 +418,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Pro 9 */ + { "MSHW0343", (unsigned long)ssam_node_group_sp9 }, + ++ /* Surface Pro 10 */ ++ { "MSHW0510", (unsigned long)ssam_node_group_sp10 }, ++ + /* Surface Book 2 */ + { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, + +-- +2.45.1 + diff --git a/patches/6.9/0008-surface-sam-over-hid.patch b/patches/6.9/0008-surface-sam-over-hid.patch index 9641b25d14..4fa7cb11d6 100644 --- a/patches/6.9/0008-surface-sam-over-hid.patch +++ b/patches/6.9/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From d0d9bd15ba1c1bbe0ac57888e0592f3a39cc8268 Mon Sep 17 00:00:00 2001 +From 62692a1aeb782ea036a05638ea726e1f3ca5d355 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -110,7 +110,7 @@ index 14ae0cfc325ef..a3a9f81fb47ff 100644 -- 2.45.1 -From 9ff8e9c9025f8a0a7e4b0b8cd1e526a4f4ff331f Mon Sep 17 00:00:00 2001 +From 7e84459d76ac641f836ed4831446be21df1ebee7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.9/0009-surface-button.patch b/patches/6.9/0009-surface-button.patch index e4f35aa787..282c3c4fce 100644 --- a/patches/6.9/0009-surface-button.patch +++ b/patches/6.9/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 23a728a730706febe949f3cb7d34c35e91f77be0 Mon Sep 17 00:00:00 2001 +From 9d868315b886f83d0eb887d0a5ffadcb90788cea Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index f6d060377d189..b8603f74eb286 100644 -- 2.45.1 -From 85b8dbc9527a74be5f87d2148c79242219cef174 Mon Sep 17 00:00:00 2001 +From 2bb3998d481e605b9733230e1dbf2a7d6ba83999 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.9/0010-surface-typecover.patch b/patches/6.9/0010-surface-typecover.patch index 62da601e36..8597657857 100644 --- a/patches/6.9/0010-surface-typecover.patch +++ b/patches/6.9/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 876520d57f820abe10ebac4ea016c696a1508196 Mon Sep 17 00:00:00 2001 +From 85296a664c811c04159d9711aa5b473bb469f55c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index b4783574b8e66..360970620589a 100644 +index 13171454f9591..a83beefd25f3f 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -39,7 +39,7 @@ index b4783574b8e66..360970620589a 100644 -- 2.45.1 -From 0de3d958b4cc82cd4e2814504f9125830d0807c5 Mon Sep 17 00:00:00 2001 +From 8335c380e55c3640cbd9342c34be2c901d837413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -272,7 +272,7 @@ index 56fc78841f245..a266449065a0a 100644 -- 2.45.1 -From 058286622357a3cdc684076c9bbae4dbbb58c5b0 Mon Sep 17 00:00:00 2001 +From c54e07fc833334829c1ba249683337e3e09ec212 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.9/0011-surface-shutdown.patch b/patches/6.9/0011-surface-shutdown.patch index 924ed0343f..f962211474 100644 --- a/patches/6.9/0011-surface-shutdown.patch +++ b/patches/6.9/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From bc69ab6e0c225a8a0dd04954209e8964ba503aba Mon Sep 17 00:00:00 2001 +From 2426c81454db39a94e544b8c29eaf3ca4cbd5230 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.9/0012-surface-gpe.patch b/patches/6.9/0012-surface-gpe.patch index 110c76bdcf..0729613bd7 100644 --- a/patches/6.9/0012-surface-gpe.patch +++ b/patches/6.9/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 90187974bb6b39b1e1d9f5994ca0e9aa20afcdc1 Mon Sep 17 00:00:00 2001 +From 0d62f4e462753400db41bd4afe964c79fbc5beeb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.9/0013-cameras.patch b/patches/6.9/0013-cameras.patch index 9496aabfa5..45577ca517 100644 --- a/patches/6.9/0013-cameras.patch +++ b/patches/6.9/0013-cameras.patch @@ -1,4 +1,4 @@ -From d85d16f63830263b7caf834e7db5b96d8a21aa8b Mon Sep 17 00:00:00 2001 +From 594b923f6a4571195fa63773639646bed2e2bb4e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index d1464324de951..5d865a34dd9db 100644 -- 2.45.1 -From 2b0dd055ffb8c8451001e4c31f15ee6eaf24f248 Mon Sep 17 00:00:00 2001 +From fb80060df68ffb77d006dffeb0d799b6b463e48c Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 61bc54299a591..a61af0f4e9fce 100644 -- 2.45.1 -From d0eb04ab5c9153e24c51bf6b1d36708a5759e159 Mon Sep 17 00:00:00 2001 +From eb3ed16ab7a069d5ecc11f6a2211caca3c574c5c Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 1e107fd49f828..e3e1696e7f0ee 100644 -- 2.45.1 -From 0cc59a0457b1b96281c4bccfda755207990acf7d Mon Sep 17 00:00:00 2001 +From 29b7931d1f73183b14b407ee2f6d1e3cdf8d2e23 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -276,7 +276,7 @@ index 07b302e093407..1d3097bc7e487 100644 -- 2.45.1 -From 089a7447da1b70a9eacf239de12f905d47dc1cfa Mon Sep 17 00:00:00 2001 +From 6319fff6505329f27cc622fb2a0b604c04ed3bd2 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -315,7 +315,7 @@ index 30f61e04ecaf5..9c1292ca85522 100644 -- 2.45.1 -From 47f4104dddf43bf9a3197a569c7e132559a6d2ce Mon Sep 17 00:00:00 2001 +From 8fe1d3b0660385751147ba14b70bf785de405768 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -366,7 +366,7 @@ index 89c7192148dfb..44eca113e7727 100644 -- 2.45.1 -From 9bd6a3b0aede46de717f298aa509e31d7d3292d0 Mon Sep 17 00:00:00 2001 +From 801bb9a48ddc1eb3ce5353d0d5c7315851efcce1 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -407,7 +407,7 @@ index e3e1696e7f0ee..423dc555093f7 100644 -- 2.45.1 -From a3703d67b8802d244efc734c7525ec568ea5e907 Mon Sep 17 00:00:00 2001 +From b5bf7bf96d471674edb3adc1ca037d22104a8151 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -448,7 +448,7 @@ index 7807fa329db00..2d2abb25b944f 100644 -- 2.45.1 -From 4cd08afc49d50db17fa7c4f58a3a341159d71c26 Mon Sep 17 00:00:00 2001 +From eb8c1aedc9f1b8ea35d575a3d5ff7cec5a038945 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -699,7 +699,7 @@ index 0000000000000..35aeb5db89c8f -- 2.45.1 -From 0dfd0e9d881e7f2fa8fde4eca34d8c235612321e Mon Sep 17 00:00:00 2001 +From f4f947cb92583d5358a128c8d9f3508b5af9124c Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -746,7 +746,7 @@ index 3df58eb3e8822..81aff2d5d8988 100644 -- 2.45.1 -From c4e3d2d301a489fda30c6079d3f0e5fd93057f3a Mon Sep 17 00:00:00 2001 +From c3495660cd36f2dca4371530ae94a42adab57f71 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.9/0014-amd-gpio.patch b/patches/6.9/0014-amd-gpio.patch index fae0741ea2..28b92fdb11 100644 --- a/patches/6.9/0014-amd-gpio.patch +++ b/patches/6.9/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From d8b96395fa7bf340be82eafb6c93e34d809d2e3a Mon Sep 17 00:00:00 2001 +From 7b3fa7073f0ce137fa8ed1192e37c48772705052 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 4bf82dbd2a6b5..7a8cb090c6568 100644 -- 2.45.1 -From db60b087f5f21504f65ea41d67ded72538e0f5ea Mon Sep 17 00:00:00 2001 +From bad564b5cc50539fe028ccac8b67b0896fbde7fa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.9/0015-rtc.patch b/patches/6.9/0015-rtc.patch index e23cf5e0cd..08b2bd41a1 100644 --- a/patches/6.9/0015-rtc.patch +++ b/patches/6.9/0015-rtc.patch @@ -1,4 +1,4 @@ -From 577071626f93a9e3f973351810fdb0082e9c00e9 Mon Sep 17 00:00:00 2001 +From 0d942a7b3bc0613de7ae4c7583bd9625e75c203a Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From a417ec8e4de3f5e8fef774622478ef73cbdcd702 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 18 Jul 2024 22:50:38 +0200 Subject: [PATCH 030/236] Update Arch kernel to v6.9.9 --- pkg/arch/kernel/PKGBUILD | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 4d76b7678e..201d9825f1 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.9.7.arch1 +pkgver=6.9.9.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('e827ae94b1102cb1d752e101584e146de6e8f2b58eb75942fb9d8431b267d255' +sha256sums=('e26e4c0910dda677fd49acf9b48d20b5898f47d37e03644dbbaa01521c7c0ceb' '3acffee6493e810bd13f042b0a8e97e2b66a977b8ae7ec7c25a604446271860f' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - 'faa0347daf092b96cff43393f5b954189bb12e5582dfd949884ba23b5e9b2b5c' - '99527819e246916757bba580c9380529ab8ea231e7e3e93a2183f2e50feb4969' - '9d6c28c1f6227c2896d372bda724054231f1be5f798b97844996c76a12a908ac' - '3644d22395d544192d23594dff39377cddb891a122330cb8366f41690492b857' - '23a71c37f0ed26f9fd27a54217472738f998287edbafc423a81faf99cb3c8c61' - '97002925baeff81101c76711c29025c5efa2d743ae8cff1da4f69b46024b985d' - 'be8da43c1ddb25ba2eec9c129a07c4b5de19c04087f4d9e3b857919c78d3545a' - '2f1471d40475a724b4bb024f8d783f4ca1cce7c0f5c78a68de9eeda9543f3f32' - '6275359c380b89a9f131bd1a9ba6cfe5ee283e37ff07d350d43f7cf9a26da5f2' - '160d801d699e9f2322525970f63afe8170df1a3f045567da81a35d443d1521ef' - '7915d257d1ab92d182646f1fbb3942d9e9c3276195f748ef3f958fe15120a16b' - 'db197da01e5e0ba8682d10c16ebda8d738c4b9ef1277c874a12d22abb181bc50' - '94bbec8146debbfdc7d781742fb4f7b0b657c43d27b731c87599ceabbc471b28' - 'afb5ef163a7c57c9eb07e2c4b73da09097dedcf3d6636de06d10c7999664e1a1' - 'f061046501917285950f915c9f7c6e124cdbae3b106b2416e2c868d1e79a5898') + 'f14d2f34cc9474a130afd2241eaece2890f18970babcebc73da644a5bfcdbc6f' + '4590d2e70aeff57e5826ec78129d3c64204c7e14cbca675466d049874df77409' + '9534a110b47431f303bef18fcccd442c3c75ca4fedb826b03ebe2512396ae364' + 'd26a9d1737a86fc1c83b43761b18549d504640283a702679ae7450e16a39f5e0' + '5febaed6a68544b6611efa60b9d40888704f08e23f7be48511f305aaac91d085' + 'c4786b657649fb5b4ff26e97663993b13a383191db8cfe577ec97efea4762ad9' + 'eeab31d3906b3d37691bfa075b32e46c5bbfdfa5d36d3846c89631ad90f6791a' + '0b0fbc8e355a4bcd6470bf450c12f76bb9e84148aa2d871beb28479371e23744' + '38cb53cccda06fada526b26b44ef8b27c6043bafc2fcc2b1a8a828b330badf99' + 'e1f9ea6860ddf9980c67c48800dd2833d818d07e4c50ae6ab194af3016a3e037' + '462813550b2be2c0868a9d2901fbcc78057854ee291ca9287bfa4af6da7972af' + '129dee890fe9c31384c9b2b8c83c3849829c54ed4212c5b543e9f551ecf3cedc' + '6ebec733af1d893fb613bc5e53c885af688d099eb87cc75425b8f2991aad9f77' + '6db4054dc5859ee892fa657948d6e0fe29a813b35d2e7e4fdb45ed85e57a8875' + '2e178ce02502cb8de433f46d1efaf5f24fec1bf34185bd104d63e50c1d916609') export KBUILD_BUILD_HOST=archlinux From e4f3e0e4b831f1b950e86a30fadae21ffb7c23b3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 18 Jul 2024 22:51:20 +0200 Subject: [PATCH 031/236] Update Debian kernel to v6.9.9 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 2b51fec02d..ce3f537e3c 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.9.7" +KERNEL_VERSION="6.9.9" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 2ef315271b172d158f57e8bd39e2c81bd6a4c92b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 18 Jul 2024 22:52:54 +0200 Subject: [PATCH 032/236] Update Fedora kernels to v6.9.9 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 2c181b33f9..4525cdc90e 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.9.7-0" +PACKAGE_TAG = "kernel-6.9.9-0" ## ## The release number of the modified kernel package. From 4ebabbb234e4d243fce22185dfc3ea8c11b30138 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 3 Aug 2024 21:00:06 +0200 Subject: [PATCH 033/236] pkg/debian: Add pkg-config to dependencies --- .github/scripts/package/debian.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/package/debian.sh b/.github/scripts/package/debian.sh index 16964bd1ef..1acc652f30 100644 --- a/.github/scripts/package/debian.sh +++ b/.github/scripts/package/debian.sh @@ -29,7 +29,7 @@ setup-builddeps) apt-get update apt-get upgrade apt-get install build-essential fakeroot rsync git wget software-properties-common \ - zstd lz4 sbsigntool debhelper dpkg-dev dpkg-sig + zstd lz4 sbsigntool debhelper dpkg-dev dpkg-sig pkg-config apt-get build-dep linux # install python 3.11, required for configuring the kernel via Ubuntu's annotation format From 0004a8c1288938aaadc95d85d1ee8e5020e947f3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 3 Aug 2024 21:00:37 +0200 Subject: [PATCH 034/236] pkg/debian: Add proper fallbacks for static linking libcrypto --- pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index c58918dc6d..484968cc12 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -16,7 +16,7 @@ index bc90520a54266..1d092bfd28e3a 100644 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) -HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) -+HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto) -Wl,-Bdynamic ++HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) -Wl,-Bdynamic ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) From c7d4b132980589075e8cb9ac5e2d3759e7958ce0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 3 Aug 2024 21:17:28 +0200 Subject: [PATCH 035/236] pkg/debian: Statically link libc for sign-file --- pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index 484968cc12..d35e4fe0af 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -16,7 +16,7 @@ index bc90520a54266..1d092bfd28e3a 100644 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) -HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) -+HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) -Wl,-Bdynamic ++HOSTLDLIBS_sign-file = -Wl,-Bstatic -lc $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) -Wl,-Bdynamic ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) From a10a1dddfa09db979d1026673fd369ada4684b3b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 3 Aug 2024 23:06:32 +0200 Subject: [PATCH 036/236] Revert "pkg/debian: Statically link libc for sign-file" This reverts commit c7d4b132980589075e8cb9ac5e2d3759e7958ce0. Adding -lc breaks the final sign-file binary. --- pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index d35e4fe0af..484968cc12 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -16,7 +16,7 @@ index bc90520a54266..1d092bfd28e3a 100644 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) -HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) -+HOSTLDLIBS_sign-file = -Wl,-Bstatic -lc $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) -Wl,-Bdynamic ++HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) -Wl,-Bdynamic ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) From 79d64205cbacf5a458971eddbd047458beaaf721 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 3 Aug 2024 23:15:55 +0200 Subject: [PATCH 037/236] pkg/debian: Statically link everything for sign-file --- pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index 484968cc12..474bec014b 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -16,7 +16,7 @@ index bc90520a54266..1d092bfd28e3a 100644 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) -HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) -+HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) -Wl,-Bdynamic ++HOSTLDLIBS_sign-file = -static -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) From 6aa90169e723b3848a7f6e05997da8636c1d2206 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Aug 2024 11:40:08 +0200 Subject: [PATCH 038/236] Revert "pkg/debian: Statically link everything for sign-file" This reverts commit 79d64205cbacf5a458971eddbd047458beaaf721. --- pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index 474bec014b..484968cc12 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -16,7 +16,7 @@ index bc90520a54266..1d092bfd28e3a 100644 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) -HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) -+HOSTLDLIBS_sign-file = -static -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) ++HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) -Wl,-Bdynamic ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) From 50d1a938fc6a6630ed62eb07c71945cdb6c026e5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Aug 2024 11:41:00 +0200 Subject: [PATCH 039/236] pkg/debian: Statically link libcrypto for sign-file As suggested by quo at [1]. We need to statically link libcrypto, but dynamically link libdl. [1]: https://github.com/linux-surface/kernel/issues/134#issuecomment-2267442971 --- pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index 484968cc12..7c79eee9b1 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -16,7 +16,7 @@ index bc90520a54266..1d092bfd28e3a 100644 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) -HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) -+HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto 2> /dev/null || echo -lcrypto -ldl -pthread) -Wl,-Bdynamic ++HOSTLDLIBS_sign-file = -Wl,-Bstatic $(shell $(HOSTPKG_CONFIG) --static --libs libcrypto | sed 's/-ldl//' 2> /dev/null || echo -lcrypto) -Wl,-Bdynamic -ldl ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) From 045b511f169dc075425659abb2ce0687f6de84cd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Aug 2024 15:31:27 +0200 Subject: [PATCH 040/236] Remove outdated patches for v6.8 --- configs/surface-6.8.config | 81 - patches/6.8/0001-surface3-oemb.patch | 101 - patches/6.8/0002-mwifiex.patch | 400 -- patches/6.8/0003-ath10k.patch | 121 - patches/6.8/0004-ipts.patch | 3291 -------------- patches/6.8/0005-ithc.patch | 4340 ------------------- patches/6.8/0006-surface-sam.patch | 1218 ------ patches/6.8/0007-surface-sam-over-hid.patch | 335 -- patches/6.8/0008-surface-button.patch | 149 - patches/6.8/0009-surface-typecover.patch | 573 --- patches/6.8/0010-surface-shutdown.patch | 97 - patches/6.8/0011-surface-gpe.patch | 51 - patches/6.8/0012-cameras.patch | 852 ---- patches/6.8/0013-amd-gpio.patch | 109 - patches/6.8/0014-rtc.patch | 110 - 15 files changed, 11828 deletions(-) delete mode 100644 configs/surface-6.8.config delete mode 100644 patches/6.8/0001-surface3-oemb.patch delete mode 100644 patches/6.8/0002-mwifiex.patch delete mode 100644 patches/6.8/0003-ath10k.patch delete mode 100644 patches/6.8/0004-ipts.patch delete mode 100644 patches/6.8/0005-ithc.patch delete mode 100644 patches/6.8/0006-surface-sam.patch delete mode 100644 patches/6.8/0007-surface-sam-over-hid.patch delete mode 100644 patches/6.8/0008-surface-button.patch delete mode 100644 patches/6.8/0009-surface-typecover.patch delete mode 100644 patches/6.8/0010-surface-shutdown.patch delete mode 100644 patches/6.8/0011-surface-gpe.patch delete mode 100644 patches/6.8/0012-cameras.patch delete mode 100644 patches/6.8/0013-amd-gpio.patch delete mode 100644 patches/6.8/0014-rtc.patch diff --git a/configs/surface-6.8.config b/configs/surface-6.8.config deleted file mode 100644 index 05628a9957..0000000000 --- a/configs/surface-6.8.config +++ /dev/null @@ -1,81 +0,0 @@ -## -## Surface Aggregator Module -## -CONFIG_SURFACE_AGGREGATOR=m -# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set -CONFIG_SURFACE_AGGREGATOR_BUS=y -CONFIG_SURFACE_AGGREGATOR_CDEV=m -CONFIG_SURFACE_AGGREGATOR_HUB=m -CONFIG_SURFACE_AGGREGATOR_REGISTRY=m -CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m - -CONFIG_SURFACE_ACPI_NOTIFY=m -CONFIG_SURFACE_DTX=m -CONFIG_SURFACE_PLATFORM_PROFILE=m - -CONFIG_SURFACE_HID=m -CONFIG_SURFACE_KBD=m - -CONFIG_BATTERY_SURFACE=m -CONFIG_CHARGER_SURFACE=m - -CONFIG_SENSORS_SURFACE_TEMP=m -CONFIG_SENSORS_SURFACE_FAN=m - -## -## Surface Hotplug -## -CONFIG_SURFACE_HOTPLUG=m - -## -## IPTS and ITHC touchscreen -## -## This only enables the user interface for IPTS/ITHC data. -## For the touchscreen to work, you need to install iptsd. -## -CONFIG_HID_IPTS=m -CONFIG_HID_ITHC=m - -## -## Cameras: IPU3 -## -CONFIG_VIDEO_DW9719=m -CONFIG_VIDEO_IPU3_IMGU=m -CONFIG_VIDEO_IPU3_CIO2=m -CONFIG_IPU_BRIDGE=m -CONFIG_INTEL_SKL_INT3472=m -CONFIG_REGULATOR_TPS68470=m -CONFIG_COMMON_CLK_TPS68470=m -CONFIG_LEDS_TPS68470=m - -## -## Cameras: Sensor drivers -## -CONFIG_VIDEO_OV5693=m -CONFIG_VIDEO_OV7251=m -CONFIG_VIDEO_OV8865=m - -## -## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. -## -# CONFIG_INTEL_ATOMISP is not set - -## -## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 -## -CONFIG_APDS9960=m - -## -## Build-in UFS support (required for some Surface Go devices) -## -CONFIG_SCSI_UFSHCD=m -CONFIG_SCSI_UFSHCD_PCI=m - -## -## Other Drivers -## -CONFIG_INPUT_SOC_BUTTON_ARRAY=m -CONFIG_SURFACE_3_POWER_OPREGION=m -CONFIG_SURFACE_PRO3_BUTTON=m -CONFIG_SURFACE_GPE=m -CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m diff --git a/patches/6.8/0001-surface3-oemb.patch b/patches/6.8/0001-surface3-oemb.patch deleted file mode 100644 index 05577d4579..0000000000 --- a/patches/6.8/0001-surface3-oemb.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 45a9e7f97fc36942e3d70a78fe5313fa78733933 Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 18 Oct 2020 16:42:44 +0900 -Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI - table - -On some Surface 3, the DMI table gets corrupted for unknown reasons -and breaks existing DMI matching used for device-specific quirks. - -This commit adds the (broken) DMI data into dmi_system_id tables used -for quirks so that each driver can enable quirks even on the affected -systems. - -On affected systems, DMI data will look like this: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:OEMB - /sys/devices/virtual/dmi/id/board_vendor:OEMB - /sys/devices/virtual/dmi/id/chassis_vendor:OEMB - /sys/devices/virtual/dmi/id/product_name:OEMB - /sys/devices/virtual/dmi/id/sys_vendor:OEMB - -Expected: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:Surface 3 - /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/product_name:Surface 3 - /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation - -Signed-off-by: Tsuchiya Yuto -Patchset: surface3-oemb ---- - drivers/platform/surface/surface3-wmi.c | 7 +++++++ - sound/soc/codecs/rt5645.c | 9 +++++++++ - sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ - 3 files changed, 24 insertions(+) - -diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index c15ed7a12784..1ec8edb5aafa 100644 ---- a/drivers/platform/surface/surface3-wmi.c -+++ b/drivers/platform/surface/surface3-wmi.c -@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - #endif - { } - }; -diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 20191a4473c2..5ba599b5aba6 100644 ---- a/sound/soc/codecs/rt5645.c -+++ b/sound/soc/codecs/rt5645.c -@@ -3768,6 +3768,15 @@ static const struct dmi_system_id dmi_platform_data[] = { - }, - .driver_data = (void *)&intel_braswell_platform_data, - }, -+ { -+ .ident = "Microsoft Surface 3", -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ .driver_data = (void *)&intel_braswell_platform_data, -+ }, - { - /* - * Match for the GPDwin which unfortunately uses somewhat -diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index 5e2ec60e2954..207868c699f2 100644 ---- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .callback = cht_surface_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - { } - }; - --- -2.44.0 - diff --git a/patches/6.8/0002-mwifiex.patch b/patches/6.8/0002-mwifiex.patch deleted file mode 100644 index dd5fa2315a..0000000000 --- a/patches/6.8/0002-mwifiex.patch +++ /dev/null @@ -1,400 +0,0 @@ -From 2c7ff35a85341dcd8fa2ea575088881df9dea874 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Tue, 3 Nov 2020 13:28:04 +0100 -Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface - devices - -The most recent firmware of the 88W8897 card reports a hardcoded LTR -value to the system during initialization, probably as an (unsuccessful) -attempt of the developers to fix firmware crashes. This LTR value -prevents most of the Microsoft Surface devices from entering deep -powersaving states (either platform C-State 10 or S0ix state), because -the exit latency of that state would be higher than what the card can -tolerate. - -Turns out the card works just the same (including the firmware crashes) -no matter if that hardcoded LTR value is reported or not, so it's kind -of useless and only prevents us from saving power. - -To get rid of those hardcoded LTR reports, it's possible to reset the -PCI bridge device after initializing the cards firmware. I'm not exactly -sure why that works, maybe the power management subsystem of the PCH -resets its stored LTR values when doing a function level reset of the -bridge device. Doing the reset once after starting the wifi firmware -works very well, probably because the firmware only reports that LTR -value a single time during firmware startup. - -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 3 files changed, 31 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 5f997becdbaa..9a9929424513 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) - static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) - { - struct pcie_service_card *card = adapter->card; -+ struct pci_dev *pdev = card->dev; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; - -+ /* Trigger a function level reset of the PCI bridge device, this makes -+ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value -+ * that prevents the system from entering package C10 and S0ix powersaving -+ * states. -+ * We need to do it here because it must happen after firmware -+ * initialization and this function is called after that is done. -+ */ -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ pci_reset_function(parent_pdev); -+ - /* Write the RX ring read pointer in to reg->rx_rdptr */ - mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); - } -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5", -@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 6", -@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 1", -@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 2", -@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 1", -@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 2", -@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - {} - }; -@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "no quirks enabled\n"); - if (card->quirks & QUIRK_FW_RST_D3COLD) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); - } - - static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -4,6 +4,7 @@ - #include "pcie.h" - - #define QUIRK_FW_RST_D3COLD BIT(0) -+#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) - - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.44.0 - -From 4a326d9e87d1dc4945903560d3d22fbd69a8962c Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 4 Oct 2020 00:11:49 +0900 -Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ - -Currently, mwifiex fw will crash after suspend on recent kernel series. -On Windows, it seems that the root port of wifi will never enter D3 state -(stay on D0 state). And on Linux, disabling the D3 state for the -bridge fixes fw crashing after suspend. - -This commit disables the D3 state of root port on driver initialization -and fixes fw crashing after suspend. - -Signed-off-by: Tsuchiya Yuto -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 3 files changed, 27 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 9a9929424513..2273e3029776 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) - { - struct pcie_service_card *card; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - int ret; - - pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", -@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - return -1; - } - -+ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing -+ * after suspend -+ */ -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ parent_pdev->bridge_d3 = false; -+ - return 0; - } - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5", -@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 6", -@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 1", -@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 2", -@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 1", -@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 2", -@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - {} - }; -@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); - if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) - dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ dev_info(&pdev->dev, -+ "quirk no_brigde_d3 enabled\n"); - } - - static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -5,6 +5,7 @@ - - #define QUIRK_FW_RST_D3COLD BIT(0) - #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) -+#define QUIRK_NO_BRIDGE_D3 BIT(2) - - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.44.0 - -From dddda6f9c25716dea1265f71b8286936afa192b5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 25 Mar 2021 11:33:02 +0100 -Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell - 88W8897 - -The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) -is used in a lot of Microsoft Surface devices, and all those devices -suffer from very low 2.4GHz wifi connection speeds while bluetooth is -enabled. The reason for that is that the default passive scanning -interval for Bluetooth Low Energy devices is quite high in Linux -(interval of 60 msec and scan window of 30 msec, see hci_core.c), and -the Marvell chip is known for its bad bt+wifi coexisting performance. - -So decrease that passive scan interval and make the scan window shorter -on this particular device to allow for spending more time transmitting -wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and -the new scan window is 6.25 msec (0xa * 0,625 msec). - -This change has a very large impact on the 2.4GHz wifi speeds and gets -it up to performance comparable with the Windows driver, which seems to -apply a similar quirk. - -The interval and window length were tested and found to work very well -with a lot of Bluetooth Low Energy devices, including the Surface Pen, a -Bluetooth Speaker and two modern Bluetooth headphones. All devices were -discovered immediately after turning them on. Even lower values were -also tested, but they introduced longer delays until devices get -discovered. - -Patchset: mwifiex ---- - drivers/bluetooth/btusb.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index d31edad7a056..fc08e0c51c87 100644 ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; - #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) - #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) - #define BTUSB_ACTIONS_SEMI BIT(27) -+#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) - - static const struct usb_device_id btusb_table[] = { - /* Generic Bluetooth USB device */ -@@ -468,6 +469,7 @@ static const struct usb_device_id quirks_table[] = { - { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, - { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, - { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, -+ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, - - /* Intel Bluetooth devices */ - { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4401,6 +4403,19 @@ static int btusb_probe(struct usb_interface *intf, - if (id->driver_info & BTUSB_MARVELL) - hdev->set_bdaddr = btusb_set_bdaddr_marvell; - -+ /* The Marvell 88W8897 combined wifi and bluetooth card is known for -+ * very bad bt+wifi coexisting performance. -+ * -+ * Decrease the passive BT Low Energy scan interval a bit -+ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter -+ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly -+ * higher wifi throughput while passively scanning for BT LE devices. -+ */ -+ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { -+ hdev->le_scan_interval = 0x0190; -+ hdev->le_scan_window = 0x000a; -+ } -+ - if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && - (id->driver_info & BTUSB_MEDIATEK)) { - hdev->setup = btusb_mtk_setup; --- -2.44.0 - diff --git a/patches/6.8/0003-ath10k.patch b/patches/6.8/0003-ath10k.patch deleted file mode 100644 index 3200456e59..0000000000 --- a/patches/6.8/0003-ath10k.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 7b414f11dfa0be3204b0a43b82a75744f8218d57 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 27 Feb 2021 00:45:52 +0100 -Subject: [PATCH] ath10k: Add module parameters to override board files - -Some Surface devices, specifically the Surface Go and AMD version of the -Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better -with a different board file, as it seems that the firmeware included -upstream is buggy. - -As it is generally not a good idea to randomly overwrite files, let -alone doing so via packages, we add module parameters to override those -file names in the driver. This allows us to package/deploy the override -via a modprobe.d config. - -Signed-off-by: Maximilian Luz -Patchset: ath10k ---- - drivers/net/wireless/ath/ath10k/core.c | 58 ++++++++++++++++++++++++++ - 1 file changed, 58 insertions(+) - -diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 0032f8aa892f..17717b53316b 100644 ---- a/drivers/net/wireless/ath/ath10k/core.c -+++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -39,6 +39,9 @@ static bool fw_diag_log; - /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ - unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; - -+static char *override_board = ""; -+static char *override_board2 = ""; -+ - unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | - BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); - -@@ -51,6 +54,9 @@ module_param(fw_diag_log, bool, 0644); - module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); - module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); - -+module_param(override_board, charp, 0644); -+module_param(override_board2, charp, 0644); -+ - MODULE_PARM_DESC(debug_mask, "Debugging mask"); - MODULE_PARM_DESC(uart_print, "Uart target debugging"); - MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); -@@ -60,6 +66,9 @@ MODULE_PARM_DESC(frame_mode, - MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); - MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); - -+MODULE_PARM_DESC(override_board, "Override for board.bin file"); -+MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); -+ - static const struct ath10k_hw_params ath10k_hw_params_list[] = { - { - .id = QCA988X_HW_2_0_VERSION, -@@ -928,6 +937,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) - return 0; - } - -+static const char *ath10k_override_board_fw_file(struct ath10k *ar, -+ const char *file) -+{ -+ if (strcmp(file, "board.bin") == 0) { -+ if (strcmp(override_board, "") == 0) -+ return file; -+ -+ if (strcmp(override_board, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); -+ return NULL; -+ } -+ -+ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", -+ override_board); -+ -+ return override_board; -+ } -+ -+ if (strcmp(file, "board-2.bin") == 0) { -+ if (strcmp(override_board2, "") == 0) -+ return file; -+ -+ if (strcmp(override_board2, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); -+ return NULL; -+ } -+ -+ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", -+ override_board2); -+ -+ return override_board2; -+ } -+ -+ return file; -+} -+ - static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - const char *dir, - const char *file) -@@ -942,6 +987,19 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - if (dir == NULL) - dir = "."; - -+ /* HACK: Override board.bin and board-2.bin files if specified. -+ * -+ * Some Surface devices perform better with a different board -+ * configuration. To this end, one would need to replace the board.bin -+ * file with the modified config and remove the board-2.bin file. -+ * Unfortunately, that's not a solution that we can easily package. So -+ * we add module options to perform these overrides here. -+ */ -+ -+ file = ath10k_override_board_fw_file(ar, file); -+ if (!file) -+ return ERR_PTR(-ENOENT); -+ - snprintf(filename, sizeof(filename), "%s/%s", dir, file); - ret = firmware_request_nowarn(&fw, filename, ar->dev); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", --- -2.44.0 - diff --git a/patches/6.8/0004-ipts.patch b/patches/6.8/0004-ipts.patch deleted file mode 100644 index bab19d1d3c..0000000000 --- a/patches/6.8/0004-ipts.patch +++ /dev/null @@ -1,3291 +0,0 @@ -From 4a1fdfebd3e84fe581b512f73bbc551ec9e2d0e8 Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Thu, 30 Jul 2020 13:21:53 +0200 -Subject: [PATCH] mei: me: Add Icelake device ID for iTouch - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/misc/mei/hw-me-regs.h | 1 + - drivers/misc/mei/pci-me.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index aac36750d2c5..2ba8db8a9583 100644 ---- a/drivers/misc/mei/hw-me-regs.h -+++ b/drivers/misc/mei/hw-me-regs.h -@@ -92,6 +92,7 @@ - #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ - - #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ -+#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ - #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ - - #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ -diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 8cf636c54032..078d3e773cda 100644 ---- a/drivers/misc/mei/pci-me.c -+++ b/drivers/misc/mei/pci-me.c -@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { - {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, -+ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, --- -2.44.0 - -From b1e22125c8f241f49cc3a6b7eaa0b6430bb1f1ce Mon Sep 17 00:00:00 2001 -From: Liban Hannan -Date: Tue, 12 Apr 2022 23:31:12 +0100 -Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS - -Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. -Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: - -DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr -0x104ea3000 [fault reason 0x06] PTE Read access is not set - -This is very similar to the bug described at: -https://bugs.launchpad.net/bugs/1958004 - -Fixed with the following patch which this patch basically copies: -https://launchpadlibrarian.net/586396847/43255ca.diff - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 11652e0bcab3..6c01b1aebf27 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -40,6 +40,11 @@ - #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) - #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) - -+#define IS_IPTS(pdev) ( \ -+ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ -+ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ -+ ) -+ - #define IOAPIC_RANGE_START (0xfee00000) - #define IOAPIC_RANGE_END (0xfeefffff) - #define IOVA_START_ADDR (0x1000) -@@ -148,12 +153,14 @@ int intel_iommu_enabled = 0; - EXPORT_SYMBOL_GPL(intel_iommu_enabled); - - static int dmar_map_gfx = 1; -+static int dmar_map_ipts = 1; - static int intel_iommu_superpage = 1; - static int iommu_identity_mapping; - static int iommu_skip_te_disable; - - #define IDENTMAP_GFX 2 - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPTS 16 - - const struct iommu_ops intel_iommu_ops; - static const struct iommu_dirty_ops intel_dirty_ops; -@@ -2412,6 +2419,9 @@ static int device_def_domain_type(struct device *dev) - - if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev)) - return IOMMU_DOMAIN_IDENTITY; -+ -+ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; - } - - return 0; -@@ -2719,6 +2729,9 @@ static int __init init_dmars(void) - if (!dmar_map_gfx) - iommu_identity_mapping |= IDENTMAP_GFX; - -+ if (!dmar_map_ipts) -+ iommu_identity_mapping |= IDENTMAP_IPTS; -+ - check_tylersburg_isoch(); - - ret = si_domain_init(hw_pass_through); -@@ -4896,6 +4909,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - dmar_map_gfx = 0; - } - -+static void quirk_iommu_ipts(struct pci_dev *dev) -+{ -+ if (!IS_IPTS(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; -+ -+ pci_info(dev, "Disabling IOMMU for IPTS\n"); -+ dmar_map_ipts = 0; -+} -+ - /* G4x/GM45 integrated gfx dmar support is totally busted. */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4931,6 +4956,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); - -+/* disable IPTS dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -+ - static void quirk_iommu_rwbf(struct pci_dev *dev) - { - if (risky_device(dev)) --- -2.44.0 - -From fa7796bc06659b87f47d8921d0441314612870b9 Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Sun, 11 Dec 2022 12:00:59 +0100 -Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus - -Based on linux-surface/intel-precise-touch@8abe268 - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 2 + - drivers/hid/ipts/Kconfig | 14 + - drivers/hid/ipts/Makefile | 16 ++ - drivers/hid/ipts/cmd.c | 61 +++++ - drivers/hid/ipts/cmd.h | 60 ++++ - drivers/hid/ipts/context.h | 52 ++++ - drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ - drivers/hid/ipts/control.h | 126 +++++++++ - drivers/hid/ipts/desc.h | 80 ++++++ - drivers/hid/ipts/eds1.c | 103 +++++++ - drivers/hid/ipts/eds1.h | 35 +++ - drivers/hid/ipts/eds2.c | 144 ++++++++++ - drivers/hid/ipts/eds2.h | 35 +++ - drivers/hid/ipts/hid.c | 225 +++++++++++++++ - drivers/hid/ipts/hid.h | 24 ++ - drivers/hid/ipts/main.c | 126 +++++++++ - drivers/hid/ipts/mei.c | 188 +++++++++++++ - drivers/hid/ipts/mei.h | 66 +++++ - drivers/hid/ipts/receiver.c | 250 +++++++++++++++++ - drivers/hid/ipts/receiver.h | 16 ++ - drivers/hid/ipts/resources.c | 131 +++++++++ - drivers/hid/ipts/resources.h | 41 +++ - drivers/hid/ipts/spec-data.h | 100 +++++++ - drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ - drivers/hid/ipts/spec-hid.h | 34 +++ - drivers/hid/ipts/thread.c | 84 ++++++ - drivers/hid/ipts/thread.h | 59 ++++ - 28 files changed, 2850 insertions(+) - create mode 100644 drivers/hid/ipts/Kconfig - create mode 100644 drivers/hid/ipts/Makefile - create mode 100644 drivers/hid/ipts/cmd.c - create mode 100644 drivers/hid/ipts/cmd.h - create mode 100644 drivers/hid/ipts/context.h - create mode 100644 drivers/hid/ipts/control.c - create mode 100644 drivers/hid/ipts/control.h - create mode 100644 drivers/hid/ipts/desc.h - create mode 100644 drivers/hid/ipts/eds1.c - create mode 100644 drivers/hid/ipts/eds1.h - create mode 100644 drivers/hid/ipts/eds2.c - create mode 100644 drivers/hid/ipts/eds2.h - create mode 100644 drivers/hid/ipts/hid.c - create mode 100644 drivers/hid/ipts/hid.h - create mode 100644 drivers/hid/ipts/main.c - create mode 100644 drivers/hid/ipts/mei.c - create mode 100644 drivers/hid/ipts/mei.h - create mode 100644 drivers/hid/ipts/receiver.c - create mode 100644 drivers/hid/ipts/receiver.h - create mode 100644 drivers/hid/ipts/resources.c - create mode 100644 drivers/hid/ipts/resources.h - create mode 100644 drivers/hid/ipts/spec-data.h - create mode 100644 drivers/hid/ipts/spec-device.h - create mode 100644 drivers/hid/ipts/spec-hid.h - create mode 100644 drivers/hid/ipts/thread.c - create mode 100644 drivers/hid/ipts/thread.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 4c682c650704..a263e49b2ae2 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1351,4 +1351,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" - - source "drivers/hid/surface-hid/Kconfig" - -+source "drivers/hid/ipts/Kconfig" -+ - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 082a728eac60..f4bad1b8d813 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -170,3 +170,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ - obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ -+ -+obj-$(CONFIG_HID_IPTS) += ipts/ -diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig -new file mode 100644 -index 000000000000..297401bd388d ---- /dev/null -+++ b/drivers/hid/ipts/Kconfig -@@ -0,0 +1,14 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+ -+config HID_IPTS -+ tristate "Intel Precise Touch & Stylus" -+ depends on INTEL_MEI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Precise Touch & Stylus (IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ipts. -diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile -new file mode 100644 -index 000000000000..883896f68e6a ---- /dev/null -+++ b/drivers/hid/ipts/Makefile -@@ -0,0 +1,16 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+# -+# Makefile for the IPTS touchscreen driver -+# -+ -+obj-$(CONFIG_HID_IPTS) += ipts.o -+ipts-objs := cmd.o -+ipts-objs += control.o -+ipts-objs += eds1.o -+ipts-objs += eds2.o -+ipts-objs += hid.o -+ipts-objs += main.o -+ipts-objs += mei.o -+ipts-objs += receiver.o -+ipts-objs += resources.o -+ipts-objs += thread.o -diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c -new file mode 100644 -index 000000000000..63a4934bbc5f ---- /dev/null -+++ b/drivers/hid/ipts/cmd.c -@@ -0,0 +1,61 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "mei.h" -+#include "spec-device.h" -+ -+int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp, u64 timeout) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!rsp) -+ return -EFAULT; -+ -+ /* -+ * In a response, the command code will have the most significant bit flipped to 1. -+ * If code is passed to ipts_mei_recv as is, no messages will be received. -+ */ -+ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); -+ if (ret < 0) -+ return ret; -+ -+ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); -+ -+ /* -+ * Some devices will always return this error. -+ * It is allowed to ignore it and to try continuing. -+ */ -+ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) -+ rsp->status = IPTS_STATUS_SUCCESS; -+ -+ return 0; -+} -+ -+int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) -+{ -+ struct ipts_command cmd = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.cmd = code; -+ -+ if (data && size > 0) -+ memcpy(cmd.payload, data, size); -+ -+ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); -+ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); -+} -diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h -new file mode 100644 -index 000000000000..2b4079075b64 ---- /dev/null -+++ b/drivers/hid/ipts/cmd.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CMD_H -+#define IPTS_CMD_H -+ -+#include -+ -+#include "context.h" -+#include "spec-device.h" -+ -+/* -+ * The default timeout for receiving responses -+ */ -+#define IPTS_CMD_DEFAULT_TIMEOUT 1000 -+ -+/** -+ * ipts_cmd_recv_timeout() - Receives a response to a command. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command / response. -+ * @rsp: The address that the received response will be copied to. -+ * @timeout: How many milliseconds the function will wait at most. -+ * -+ * A negative timeout means to wait forever. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp, u64 timeout); -+ -+/** -+ * ipts_cmd_recv() - Receives a response to a command. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command / response. -+ * @rsp: The address that the received response will be copied to. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp) -+{ -+ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); -+} -+ -+/** -+ * ipts_cmd_send() - Executes a command on the device. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command to execute. -+ * @data: The payload containing parameters for the command. -+ * @size: The size of the payload. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); -+ -+#endif /* IPTS_CMD_H */ -diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h -new file mode 100644 -index 000000000000..ba33259f1f7c ---- /dev/null -+++ b/drivers/hid/ipts/context.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CONTEXT_H -+#define IPTS_CONTEXT_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mei.h" -+#include "resources.h" -+#include "spec-device.h" -+#include "thread.h" -+ -+struct ipts_context { -+ struct device *dev; -+ struct ipts_mei mei; -+ -+ enum ipts_mode mode; -+ -+ /* -+ * Prevents concurrent GET_FEATURE reports. -+ */ -+ struct mutex feature_lock; -+ struct completion feature_event; -+ -+ /* -+ * These are not inside of struct ipts_resources -+ * because they don't own the memory they point to. -+ */ -+ struct ipts_buffer feature_report; -+ struct ipts_buffer descriptor; -+ -+ bool hid_active; -+ struct hid_device *hid; -+ -+ struct ipts_device_info info; -+ struct ipts_resources resources; -+ -+ struct ipts_thread receiver_loop; -+}; -+ -+#endif /* IPTS_CONTEXT_H */ -diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c -new file mode 100644 -index 000000000000..5360842d260b ---- /dev/null -+++ b/drivers/hid/ipts/control.c -@@ -0,0 +1,486 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "hid.h" -+#include "receiver.h" -+#include "resources.h" -+#include "spec-data.h" -+#include "spec-device.h" -+ -+static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!info) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ memcpy(info, rsp.payload, sizeof(*info)); -+ return 0; -+} -+ -+static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ struct ipts_set_mode cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.mode = mode; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) -+{ -+ int i = 0; -+ int ret = 0; -+ struct ipts_mem_window cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); -+ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); -+ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); -+ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); -+ } -+ -+ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); -+ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); -+ -+ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); -+ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); -+ -+ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); -+ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); -+ -+ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; -+ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+static int ipts_control_get_descriptor(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_data_header *header = NULL; -+ struct ipts_get_descriptor cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->resources.descriptor.address) -+ return -EFAULT; -+ -+ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); -+ -+ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); -+ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); -+ cmd.magic = 8; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ header = (struct ipts_data_header *)ipts->resources.descriptor.address; -+ -+ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { -+ ipts->descriptor.address = &header->data[8]; -+ ipts->descriptor.size = header->size - 8; -+ -+ return 0; -+ } -+ -+ return -ENODATA; -+} -+ -+int ipts_control_request_flush(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_quiesce_io cmd = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); -+ if (ret) -+ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_control_wait_flush(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status == IPTS_STATUS_TIMEOUT) -+ return -EAGAIN; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_request_data(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); -+ if (ret) -+ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!shutdown) -+ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); -+ else -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); -+ -+ if (ret) { -+ if (ret != -EAGAIN) -+ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); -+ -+ return ret; -+ } -+ -+ /* -+ * During shutdown, it is possible that the sensor has already been disabled. -+ */ -+ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) -+ return 0; -+ -+ if (rsp.status == IPTS_STATUS_TIMEOUT) -+ return -EAGAIN; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) -+{ -+ int ret = 0; -+ struct ipts_feedback cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.buffer = buffer; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * We don't know what feedback data looks like so we are sending zeros. -+ * See also ipts_control_refill_buffer. -+ */ -+ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) -+ return 0; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, -+ enum ipts_feedback_data_type type, void *data, size_t size) -+{ -+ struct ipts_feedback_header *header = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->resources.hid2me.address) -+ return -EFAULT; -+ -+ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); -+ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; -+ -+ header->cmd_type = cmd; -+ header->data_type = type; -+ header->size = size; -+ header->buffer = IPTS_HID2ME_BUFFER; -+ -+ if (size + sizeof(*header) > ipts->resources.hid2me.size) -+ return -EINVAL; -+ -+ if (data && size > 0) -+ memcpy(header->payload, data, size); -+ -+ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); -+} -+ -+int ipts_control_start(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_device_info info = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "Starting IPTS\n"); -+ -+ ret = ipts_control_get_device_info(ipts, &info); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); -+ return ret; -+ } -+ -+ ipts->info = info; -+ -+ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); -+ return ret; -+ } -+ -+ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); -+ -+ /* -+ * Handle newer devices -+ */ -+ if (info.intf_eds > 1) { -+ /* -+ * Fetching the descriptor will only work on newer devices. -+ * For older devices, a fallback descriptor will be used. -+ */ -+ ret = ipts_control_get_descriptor(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * Newer devices can be directly initialized in polling mode. -+ */ -+ ipts->mode = IPTS_MODE_POLL; -+ } -+ -+ ret = ipts_control_set_mode(ipts, ipts->mode); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_set_mem_window(ipts, &ipts->resources); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_receiver_start(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_request_data(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request data: %d\n", ret); -+ return ret; -+ } -+ -+ ipts_hid_enable(ipts); -+ -+ ret = ipts_hid_init(ipts, info); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int _ipts_control_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ipts_hid_disable(ipts); -+ dev_info(ipts->dev, "Stopping IPTS\n"); -+ -+ ret = ipts_receiver_stop(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_resources_free(&ipts->resources); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ ret = _ipts_control_stop(ipts); -+ if (ret) -+ return ret; -+ -+ ret = ipts_hid_free(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_restart(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ ret = _ipts_control_stop(ipts); -+ if (ret) -+ return ret; -+ -+ /* -+ * Wait a second to give the sensor time to fully shut down. -+ */ -+ msleep(1000); -+ -+ ret = ipts_control_start(ipts); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h -new file mode 100644 -index 000000000000..26629c5144ed ---- /dev/null -+++ b/drivers/hid/ipts/control.h -@@ -0,0 +1,126 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CONTROL_H -+#define IPTS_CONTROL_H -+ -+#include -+ -+#include "context.h" -+#include "spec-data.h" -+#include "spec-device.h" -+ -+/** -+ * ipts_control_request_flush() - Stop the data flow. -+ * @ipts: The IPTS driver context. -+ * -+ * Runs the command to stop the data flow on the device. -+ * All outstanding data needs to be acknowledged using feedback before the command will return. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_request_flush(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_flush() - Wait until data flow has been stopped. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_wait_flush(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_request_data(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_data() - Wait until new data is available. -+ * @ipts: The IPTS driver context. -+ * @block: Whether to block execution until data is available. -+ * -+ * In poll mode, this function will never return while the data flow is active. Instead, -+ * the poll will be incremented when new data is available. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. -+ */ -+int ipts_control_wait_data(struct ipts_context *ipts, bool block); -+ -+/** -+ * ipts_control_send_feedback() - Submits a feedback buffer to the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The ID of the buffer containing feedback data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); -+ -+/** -+ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. -+ * @ipts: The IPTS driver context. -+ * @cmd: The command that will be run on the device. -+ * @type: The type of the payload that is sent to the device. -+ * @data: The payload of the feedback command. -+ * @size: The size of the payload. -+ * -+ * HID2ME feedback is a special type of feedback, because it allows interfacing with -+ * the HID API of the device at any moment, without requiring a buffer that has to -+ * be acknowledged. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, -+ enum ipts_feedback_data_type type, void *data, size_t size); -+ -+/** -+ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer that has been processed and can be refilled. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) -+{ -+ /* -+ * IPTS expects structured data in the feedback buffer matching the buffer that will be -+ * refilled. We don't know what that data looks like, so we just keep the buffer empty. -+ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. -+ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling -+ * the buffers on some devices. -+ */ -+ -+ return ipts_control_send_feedback(ipts, buffer); -+} -+ -+/** -+ * ipts_control_start() - Initialized the device and starts the data flow. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_start(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_stop() - Stops the data flow and resets the device. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_stop(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_restart() - Stops the device and starts it again. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_restart(struct ipts_context *ipts); -+ -+#endif /* IPTS_CONTROL_H */ -diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h -new file mode 100644 -index 000000000000..307438c7c80c ---- /dev/null -+++ b/drivers/hid/ipts/desc.h -@@ -0,0 +1,80 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_DESC_H -+#define IPTS_DESC_H -+ -+#include -+ -+#define IPTS_HID_REPORT_SINGLETOUCH 64 -+#define IPTS_HID_REPORT_DATA 65 -+#define IPTS_HID_REPORT_SET_MODE 66 -+ -+#define IPTS_HID_REPORT_DATA_SIZE 7485 -+ -+/* -+ * HID descriptor for singletouch data. -+ * This descriptor should be present on all IPTS devices. -+ */ -+static const u8 ipts_singletouch_descriptor[] = { -+ 0x05, 0x0D, /* Usage Page (Digitizer), */ -+ 0x09, 0x04, /* Usage (Touchscreen), */ -+ 0xA1, 0x01, /* Collection (Application), */ -+ 0x85, 0x40, /* Report ID (64), */ -+ 0x09, 0x42, /* Usage (Tip Switch), */ -+ 0x15, 0x00, /* Logical Minimum (0), */ -+ 0x25, 0x01, /* Logical Maximum (1), */ -+ 0x75, 0x01, /* Report Size (1), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x95, 0x07, /* Report Count (7), */ -+ 0x81, 0x03, /* Input (Constant, Variable), */ -+ 0x05, 0x01, /* Usage Page (Desktop), */ -+ 0x09, 0x30, /* Usage (X), */ -+ 0x75, 0x10, /* Report Size (16), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0xA4, /* Push, */ -+ 0x55, 0x0E, /* Unit Exponent (14), */ -+ 0x65, 0x11, /* Unit (Centimeter), */ -+ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ -+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x09, 0x31, /* Usage (Y), */ -+ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ -+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0xB4, /* Pop, */ -+ 0xC0, /* End Collection */ -+}; -+ -+/* -+ * Fallback HID descriptor for older devices that do not have -+ * the ability to query their HID descriptor. -+ */ -+static const u8 ipts_fallback_descriptor[] = { -+ 0x05, 0x0D, /* Usage Page (Digitizer), */ -+ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ -+ 0xA1, 0x01, /* Collection (Application), */ -+ 0x85, 0x41, /* Report ID (65), */ -+ 0x09, 0x56, /* Usage (Scan Time), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0x75, 0x10, /* Report Size (16), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x09, 0x61, /* Usage (Gesture Char Quality), */ -+ 0x75, 0x08, /* Report Size (8), */ -+ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ -+ 0x81, 0x03, /* Input (Constant, Variable), */ -+ 0x85, 0x42, /* Report ID (66), */ -+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ -+ 0x09, 0xC8, /* Usage (C8h), */ -+ 0x75, 0x08, /* Report Size (8), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0xB1, 0x02, /* Feature (Variable), */ -+ 0xC0, /* End Collection, */ -+}; -+ -+#endif /* IPTS_DESC_H */ -diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c -new file mode 100644 -index 000000000000..ecbb3a8bdaf6 ---- /dev/null -+++ b/drivers/hid/ipts/eds1.c -@@ -0,0 +1,103 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "spec-device.h" -+ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, -+ sizeof(ipts_fallback_descriptor)); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == mode) -+ return 0; -+ -+ ipts->mode = mode; -+ -+ ret = ipts_control_restart(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_id != IPTS_HID_REPORT_SET_MODE) -+ return -EIO; -+ -+ if (report_type != HID_FEATURE_REPORT) -+ return -EIO; -+ -+ if (size != 2) -+ return -EINVAL; -+ -+ /* -+ * Implement mode switching report for older devices without native HID support. -+ */ -+ -+ if (request_type == HID_REQ_GET_REPORT) { -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ buffer[1] = ipts->mode; -+ } else if (request_type == HID_REQ_SET_REPORT) { -+ return ipts_eds1_switch_mode(ipts, buffer[1]); -+ } else { -+ return -EIO; -+ } -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h -new file mode 100644 -index 000000000000..eeeb6575e3e8 ---- /dev/null -+++ b/drivers/hid/ipts/eds1.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "context.h" -+ -+/** -+ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds1_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type); -diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c -new file mode 100644 -index 000000000000..198dc65d7887 ---- /dev/null -+++ b/drivers/hid/ipts/eds2.c -@@ -0,0 +1,144 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "spec-data.h" -+ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, -+ ipts->descriptor.size); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ mutex_lock(&ipts->feature_lock); -+ -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ -+ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); -+ reinit_completion(&ipts->feature_event); -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ goto out; -+ } -+ -+ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); -+ if (ret == 0) { -+ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ if (!ipts->feature_report.address) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (ipts->feature_report.size > size) { -+ ret = -ETOOSMALL; -+ goto out; -+ } -+ -+ ret = ipts->feature_report.size; -+ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); -+ -+out: -+ mutex_unlock(&ipts->feature_lock); -+ return ret; -+} -+ -+static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ buffer[0] = report_id; -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; -+ else -+ return -EIO; -+ -+ if (request_type == HID_REQ_GET_REPORT) -+ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); -+ else -+ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); -+} -diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h -new file mode 100644 -index 000000000000..064e3716907a ---- /dev/null -+++ b/drivers/hid/ipts/eds2.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "context.h" -+ -+/** -+ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds2_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type); -diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c -new file mode 100644 -index 000000000000..e34a1a4f9fa7 ---- /dev/null -+++ b/drivers/hid/ipts/hid.c -@@ -0,0 +1,225 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "desc.h" -+#include "eds1.h" -+#include "eds2.h" -+#include "hid.h" -+#include "spec-data.h" -+#include "spec-hid.h" -+ -+void ipts_hid_enable(struct ipts_context *ipts) -+{ -+ WRITE_ONCE(ipts->hid_active, true); -+} -+ -+void ipts_hid_disable(struct ipts_context *ipts) -+{ -+ WRITE_ONCE(ipts->hid_active, false); -+} -+ -+static int ipts_hid_start(struct hid_device *hid) -+{ -+ return 0; -+} -+ -+static void ipts_hid_stop(struct hid_device *hid) -+{ -+} -+ -+static int ipts_hid_parse(struct hid_device *hid) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ u8 *buffer = NULL; -+ size_t size = 0; -+ -+ if (!hid) -+ return -ENODEV; -+ -+ ipts = hid->driver_data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ if (ipts->info.intf_eds == 1) -+ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); -+ else -+ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ ret = hid_parse_report(hid, buffer, size); -+ kfree(buffer); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, -+ size_t size, unsigned char report_type, int request_type) -+{ -+ struct ipts_context *ipts = NULL; -+ -+ if (!hid) -+ return -ENODEV; -+ -+ ipts = hid->driver_data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ if (ipts->info.intf_eds == 1) { -+ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } else { -+ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } -+} -+ -+static struct hid_ll_driver ipts_hid_driver = { -+ .start = ipts_hid_start, -+ .stop = ipts_hid_stop, -+ .open = ipts_hid_start, -+ .close = ipts_hid_stop, -+ .parse = ipts_hid_parse, -+ .raw_request = ipts_hid_raw_request, -+}; -+ -+int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) -+{ -+ u8 *temp = NULL; -+ struct ipts_hid_header *frame = NULL; -+ struct ipts_data_header *header = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->hid) -+ return -ENODEV; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; -+ -+ temp = ipts->resources.report.address; -+ memset(temp, 0, ipts->resources.report.size); -+ -+ if (!header) -+ return -EFAULT; -+ -+ if (header->size == 0) -+ return 0; -+ -+ if (header->type == IPTS_DATA_TYPE_HID) -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); -+ -+ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { -+ ipts->feature_report.address = header->data; -+ ipts->feature_report.size = header->size; -+ -+ complete_all(&ipts->feature_event); -+ return 0; -+ } -+ -+ if (header->type != IPTS_DATA_TYPE_FRAME) -+ return 0; -+ -+ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) -+ return -ERANGE; -+ -+ /* -+ * Synthesize a HID report matching the devices that natively send HID reports -+ */ -+ temp[0] = IPTS_HID_REPORT_DATA; -+ -+ frame = (struct ipts_hid_header *)&temp[3]; -+ frame->type = IPTS_HID_FRAME_TYPE_RAW; -+ frame->size = header->size + sizeof(*frame); -+ -+ memcpy(frame->data, header->data, header->size); -+ -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); -+} -+ -+int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->hid) -+ return 0; -+ -+ ipts->hid = hid_allocate_device(); -+ if (IS_ERR(ipts->hid)) { -+ int err = PTR_ERR(ipts->hid); -+ -+ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); -+ return err; -+ } -+ -+ ipts->hid->driver_data = ipts; -+ ipts->hid->dev.parent = ipts->dev; -+ ipts->hid->ll_driver = &ipts_hid_driver; -+ -+ ipts->hid->vendor = info.vendor; -+ ipts->hid->product = info.product; -+ ipts->hid->group = HID_GROUP_GENERIC; -+ -+ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, -+ info.product); -+ -+ ret = hid_add_device(ipts->hid); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); -+ ipts_hid_free(ipts); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_hid_free(struct ipts_context *ipts) -+{ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->hid) -+ return 0; -+ -+ hid_destroy_device(ipts->hid); -+ ipts->hid = NULL; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h -new file mode 100644 -index 000000000000..1ebe77447903 ---- /dev/null -+++ b/drivers/hid/ipts/hid.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_HID_H -+#define IPTS_HID_H -+ -+#include -+ -+#include "context.h" -+#include "spec-device.h" -+ -+void ipts_hid_enable(struct ipts_context *ipts); -+void ipts_hid_disable(struct ipts_context *ipts); -+ -+int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); -+ -+int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); -+int ipts_hid_free(struct ipts_context *ipts); -+ -+#endif /* IPTS_HID_H */ -diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c -new file mode 100644 -index 000000000000..fb5b5c13ee3e ---- /dev/null -+++ b/drivers/hid/ipts/main.c -@@ -0,0 +1,126 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "mei.h" -+#include "receiver.h" -+#include "spec-device.h" -+ -+/* -+ * The MEI client ID for IPTS functionality. -+ */ -+#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) -+ -+static int ipts_set_dma_mask(struct mei_cl_device *cldev) -+{ -+ if (!cldev) -+ return -EFAULT; -+ -+ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) -+ return 0; -+ -+ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); -+} -+ -+static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) -+ return -EFAULT; -+ -+ ret = ipts_set_dma_mask(cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mei_cldev_enable(cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); -+ return ret; -+ } -+ -+ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); -+ if (!ipts) { -+ mei_cldev_disable(cldev); -+ return -ENOMEM; -+ } -+ -+ ret = ipts_mei_init(&ipts->mei, cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); -+ return ret; -+ } -+ -+ ipts->dev = &cldev->dev; -+ ipts->mode = IPTS_MODE_EVENT; -+ -+ mutex_init(&ipts->feature_lock); -+ init_completion(&ipts->feature_event); -+ -+ mei_cldev_set_drvdata(cldev, ipts); -+ -+ ret = ipts_control_start(ipts); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void ipts_remove(struct mei_cl_device *cldev) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) { -+ pr_err("MEI device is NULL!"); -+ return; -+ } -+ -+ ipts = mei_cldev_get_drvdata(cldev); -+ -+ ret = ipts_control_stop(ipts); -+ if (ret) -+ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); -+ -+ mei_cldev_disable(cldev); -+} -+ -+static struct mei_cl_device_id ipts_device_id_table[] = { -+ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(mei, ipts_device_id_table); -+ -+static struct mei_cl_driver ipts_driver = { -+ .id_table = ipts_device_id_table, -+ .name = "ipts", -+ .probe = ipts_probe, -+ .remove = ipts_remove, -+}; -+module_mei_cl_driver(ipts_driver); -+ -+MODULE_DESCRIPTION("IPTS touchscreen driver"); -+MODULE_AUTHOR("Dorian Stoll "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c -new file mode 100644 -index 000000000000..1e0395ceae4a ---- /dev/null -+++ b/drivers/hid/ipts/mei.c -@@ -0,0 +1,188 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "mei.h" -+ -+static void locked_list_add(struct list_head *new, struct list_head *head, -+ struct rw_semaphore *lock) -+{ -+ down_write(lock); -+ list_add(new, head); -+ up_write(lock); -+} -+ -+static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) -+{ -+ down_write(lock); -+ list_del(entry); -+ up_write(lock); -+} -+ -+static void ipts_mei_incoming(struct mei_cl_device *cldev) -+{ -+ ssize_t ret = 0; -+ struct ipts_mei_message *entry = NULL; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) { -+ pr_err("MEI device is NULL!"); -+ return; -+ } -+ -+ ipts = mei_cldev_get_drvdata(cldev); -+ if (!ipts) { -+ pr_err("IPTS driver context is NULL!"); -+ return; -+ } -+ -+ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); -+ if (!entry) -+ return; -+ -+ INIT_LIST_HEAD(&entry->list); -+ -+ do { -+ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); -+ } while (ret == -EINTR); -+ -+ if (ret < 0) { -+ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); -+ return; -+ } -+ -+ if (ret == 0) { -+ dev_err(ipts->dev, "Received empty response\n"); -+ return; -+ } -+ -+ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); -+ wake_up_all(&ipts->mei.message_queue); -+} -+ -+static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, -+ struct ipts_response *rsp) -+{ -+ struct ipts_mei_message *entry = NULL; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!rsp) -+ return -EFAULT; -+ -+ down_read(&mei->message_lock); -+ -+ /* -+ * Iterate over the list of received messages, and check if there is one -+ * matching the requested command code. -+ */ -+ list_for_each_entry(entry, &mei->messages, list) { -+ if (entry->rsp.cmd == code) -+ break; -+ } -+ -+ up_read(&mei->message_lock); -+ -+ /* -+ * If entry is not the list head, this means that the loop above has been stopped early, -+ * and that we found a matching element. We drop the message from the list and return it. -+ */ -+ if (!list_entry_is_head(entry, &mei->messages, list)) { -+ locked_list_del(&entry->list, &mei->message_lock); -+ -+ *rsp = entry->rsp; -+ devm_kfree(&mei->cldev->dev, entry); -+ -+ return 0; -+ } -+ -+ return -EAGAIN; -+} -+ -+int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, -+ u64 timeout) -+{ -+ int ret = 0; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ /* -+ * A timeout of 0 means check and return immideately. -+ */ -+ if (timeout == 0) -+ return ipts_mei_search(mei, code, rsp); -+ -+ /* -+ * A timeout of less than 0 means to wait forever. -+ */ -+ if (timeout < 0) { -+ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); -+ return 0; -+ } -+ -+ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, -+ msecs_to_jiffies(timeout)); -+ -+ if (ret > 0) -+ return 0; -+ -+ return -EAGAIN; -+} -+ -+int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) -+{ -+ int ret = 0; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!mei->cldev) -+ return -EFAULT; -+ -+ if (!data) -+ return -EFAULT; -+ -+ do { -+ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); -+ } while (ret == -EINTR); -+ -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) -+{ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!cldev) -+ return -EFAULT; -+ -+ mei->cldev = cldev; -+ -+ INIT_LIST_HEAD(&mei->messages); -+ init_waitqueue_head(&mei->message_queue); -+ init_rwsem(&mei->message_lock); -+ -+ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h -new file mode 100644 -index 000000000000..973bade6b0fd ---- /dev/null -+++ b/drivers/hid/ipts/mei.h -@@ -0,0 +1,66 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_MEI_H -+#define IPTS_MEI_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "spec-device.h" -+ -+struct ipts_mei_message { -+ struct list_head list; -+ struct ipts_response rsp; -+}; -+ -+struct ipts_mei { -+ struct mei_cl_device *cldev; -+ -+ struct list_head messages; -+ -+ wait_queue_head_t message_queue; -+ struct rw_semaphore message_lock; -+}; -+ -+/** -+ * ipts_mei_recv() - Receive data from a MEI device. -+ * @mei: The IPTS MEI device context. -+ * @code: The IPTS command code to look for. -+ * @rsp: The address that the received data will be copied to. -+ * @timeout: How many milliseconds the function will wait at most. -+ * -+ * A negative timeout means to wait forever. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, -+ u64 timeout); -+ -+/** -+ * ipts_mei_send() - Send data to a MEI device. -+ * @ipts: The IPTS MEI device context. -+ * @data: The data to send. -+ * @size: The size of the data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); -+ -+/** -+ * ipts_mei_init() - Initialize the MEI device context. -+ * @mei: The MEI device context to initialize. -+ * @cldev: The MEI device the context will be bound to. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); -+ -+#endif /* IPTS_MEI_H */ -diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -new file mode 100644 -index 000000000000..ef66c3c9db80 ---- /dev/null -+++ b/drivers/hid/ipts/receiver.c -@@ -0,0 +1,250 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "control.h" -+#include "hid.h" -+#include "resources.h" -+#include "spec-device.h" -+#include "thread.h" -+ -+static void ipts_receiver_next_doorbell(struct ipts_context *ipts) -+{ -+ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; -+ *doorbell = *doorbell + 1; -+} -+ -+static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) -+{ -+ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; -+ return *doorbell; -+} -+ -+static void ipts_receiver_backoff(time64_t last, u32 n) -+{ -+ /* -+ * If the last change was less than n seconds ago, -+ * sleep for a shorter period so that new data can be -+ * processed quickly. If there was no change for more than -+ * n seconds, sleep longer to avoid wasting CPU cycles. -+ */ -+ if (last + n > ktime_get_seconds()) -+ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); -+ else -+ msleep(200); -+} -+ -+static int ipts_receiver_event_loop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ u32 buffer = 0; -+ -+ struct ipts_context *ipts = NULL; -+ time64_t last = ktime_get_seconds(); -+ -+ if (!thread) -+ return -EFAULT; -+ -+ ipts = thread->data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "IPTS running in event mode\n"); -+ -+ while (!ipts_thread_should_stop(thread)) { -+ int i = 0; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_control_wait_data(ipts, false); -+ if (ret == -EAGAIN) -+ break; -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ continue; -+ } -+ -+ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; -+ ipts_receiver_next_doorbell(ipts); -+ -+ ret = ipts_hid_input_data(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); -+ -+ ret = ipts_control_refill_buffer(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); -+ -+ ret = ipts_control_request_data(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to request data: %d\n", ret); -+ -+ last = ktime_get_seconds(); -+ } -+ -+ ipts_receiver_backoff(last, 5); -+ } -+ -+ ret = ipts_control_request_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_wait_data(ipts, true); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ ret = ipts_control_wait_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ return 0; -+} -+ -+static int ipts_receiver_poll_loop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ u32 buffer = 0; -+ -+ u32 doorbell = 0; -+ u32 lastdb = 0; -+ -+ struct ipts_context *ipts = NULL; -+ time64_t last = ktime_get_seconds(); -+ -+ if (!thread) -+ return -EFAULT; -+ -+ ipts = thread->data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "IPTS running in poll mode\n"); -+ -+ while (true) { -+ if (ipts_thread_should_stop(thread)) { -+ ret = ipts_control_request_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ doorbell = ipts_receiver_current_doorbell(ipts); -+ -+ /* -+ * After filling up one of the data buffers, IPTS will increment -+ * the doorbell. The value of the doorbell stands for the *next* -+ * buffer that IPTS is going to fill. -+ */ -+ while (lastdb != doorbell) { -+ buffer = lastdb % IPTS_BUFFERS; -+ -+ ret = ipts_hid_input_data(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); -+ -+ ret = ipts_control_refill_buffer(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); -+ -+ last = ktime_get_seconds(); -+ lastdb++; -+ } -+ -+ if (ipts_thread_should_stop(thread)) -+ break; -+ -+ ipts_receiver_backoff(last, 5); -+ } -+ -+ ret = ipts_control_wait_data(ipts, true); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ ret = ipts_control_wait_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ return 0; -+} -+ -+int ipts_receiver_start(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == IPTS_MODE_EVENT) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, -+ "ipts_event"); -+ } else if (ipts->mode == IPTS_MODE_POLL) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, -+ "ipts_poll"); -+ } else { -+ ret = -EINVAL; -+ } -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_receiver_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_thread_stop(&ipts->receiver_loop); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h -new file mode 100644 -index 000000000000..3de7da62d40c ---- /dev/null -+++ b/drivers/hid/ipts/receiver.h -@@ -0,0 +1,16 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_RECEIVER_H -+#define IPTS_RECEIVER_H -+ -+#include "context.h" -+ -+int ipts_receiver_start(struct ipts_context *ipts); -+int ipts_receiver_stop(struct ipts_context *ipts); -+ -+#endif /* IPTS_RECEIVER_H */ -diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c -new file mode 100644 -index 000000000000..cc14653b2a9f ---- /dev/null -+++ b/drivers/hid/ipts/resources.c -@@ -0,0 +1,131 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+ -+#include "desc.h" -+#include "resources.h" -+#include "spec-device.h" -+ -+static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) -+{ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (buffer->address) -+ return 0; -+ -+ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); -+ -+ if (!buffer->address) -+ return -ENOMEM; -+ -+ buffer->size = size; -+ buffer->device = dev; -+ -+ return 0; -+} -+ -+static void ipts_resources_free_buffer(struct ipts_buffer *buffer) -+{ -+ if (!buffer->address) -+ return; -+ -+ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); -+ -+ buffer->address = NULL; -+ buffer->size = 0; -+ -+ buffer->dma_address = 0; -+ buffer->device = NULL; -+} -+ -+int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) -+{ -+ int ret = 0; -+ -+ /* -+ * Some compilers (AOSP clang) complain about a redefined -+ * variable when this is declared inside of the for loop. -+ */ -+ int i = 0; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); -+ if (ret) -+ goto err; -+ } -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); -+ if (ret) -+ goto err; -+ } -+ -+ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); -+ if (ret) -+ goto err; -+ -+ if (!res->report.address) { -+ res->report.size = IPTS_HID_REPORT_DATA_SIZE; -+ res->report.address = kzalloc(res->report.size, GFP_KERNEL); -+ -+ if (!res->report.address) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } -+ -+ return 0; -+ -+err: -+ -+ ipts_resources_free(res); -+ return ret; -+} -+ -+int ipts_resources_free(struct ipts_resources *res) -+{ -+ int i = 0; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) -+ ipts_resources_free_buffer(&res->data[i]); -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) -+ ipts_resources_free_buffer(&res->feedback[i]); -+ -+ ipts_resources_free_buffer(&res->doorbell); -+ ipts_resources_free_buffer(&res->workqueue); -+ ipts_resources_free_buffer(&res->hid2me); -+ ipts_resources_free_buffer(&res->descriptor); -+ -+ kfree(res->report.address); -+ res->report.address = NULL; -+ res->report.size = 0; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h -new file mode 100644 -index 000000000000..2068e13285f0 ---- /dev/null -+++ b/drivers/hid/ipts/resources.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_RESOURCES_H -+#define IPTS_RESOURCES_H -+ -+#include -+#include -+ -+#include "spec-device.h" -+ -+struct ipts_buffer { -+ u8 *address; -+ size_t size; -+ -+ dma_addr_t dma_address; -+ struct device *device; -+}; -+ -+struct ipts_resources { -+ struct ipts_buffer data[IPTS_BUFFERS]; -+ struct ipts_buffer feedback[IPTS_BUFFERS]; -+ -+ struct ipts_buffer doorbell; -+ struct ipts_buffer workqueue; -+ struct ipts_buffer hid2me; -+ -+ struct ipts_buffer descriptor; -+ -+ // Buffer for synthesizing HID reports -+ struct ipts_buffer report; -+}; -+ -+int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); -+int ipts_resources_free(struct ipts_resources *res); -+ -+#endif /* IPTS_RESOURCES_H */ -diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h -new file mode 100644 -index 000000000000..e8dd98895a7e ---- /dev/null -+++ b/drivers/hid/ipts/spec-data.h -@@ -0,0 +1,100 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_DATA_H -+#define IPTS_SPEC_DATA_H -+ -+#include -+#include -+ -+/** -+ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. -+ */ -+enum ipts_feedback_cmd_type { -+ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, -+ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, -+ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, -+}; -+ -+/** -+ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. -+ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. -+ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. -+ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. -+ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. -+ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. -+ */ -+enum ipts_feedback_data_type { -+ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, -+ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, -+ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, -+ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, -+ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, -+}; -+ -+/** -+ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. -+ * @cmd_type: A command that should be executed on the sensor. -+ * @size: The size of the payload to be written. -+ * @buffer: The ID of the buffer that contains this feedback data. -+ * @protocol: The protocol version of the EDS. -+ * @data_type: The type of data that the buffer contains. -+ * @spi_offset: The offset at which to write the payload data to the sensor. -+ * @payload: Payload for the feedback command, or 0 if no payload is sent. -+ */ -+struct ipts_feedback_header { -+ enum ipts_feedback_cmd_type cmd_type; -+ u32 size; -+ u32 buffer; -+ u32 protocol; -+ enum ipts_feedback_data_type data_type; -+ u32 spi_offset; -+ u8 reserved[40]; -+ u8 payload[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_feedback_header) == 64); -+ -+/** -+ * enum ipts_data_type - Defines what type of data a buffer contains. -+ * @IPTS_DATA_TYPE_FRAME: Raw data frame. -+ * @IPTS_DATA_TYPE_ERROR: Error data. -+ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. -+ * @IPTS_DATA_TYPE_HID: A HID report. -+ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. -+ */ -+enum ipts_data_type { -+ IPTS_DATA_TYPE_FRAME = 0x00, -+ IPTS_DATA_TYPE_ERROR = 0x01, -+ IPTS_DATA_TYPE_VENDOR = 0x02, -+ IPTS_DATA_TYPE_HID = 0x03, -+ IPTS_DATA_TYPE_GET_FEATURES = 0x04, -+ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, -+}; -+ -+/** -+ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. -+ * @type: What data the buffer contains. -+ * @size: How much data the buffer contains. -+ * @buffer: Which buffer the data is in. -+ */ -+struct ipts_data_header { -+ enum ipts_data_type type; -+ u32 size; -+ u32 buffer; -+ u8 reserved[52]; -+ u8 data[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_data_header) == 64); -+ -+#endif /* IPTS_SPEC_DATA_H */ -diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h -new file mode 100644 -index 000000000000..41845f9d9025 ---- /dev/null -+++ b/drivers/hid/ipts/spec-device.h -@@ -0,0 +1,290 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_DEVICE_H -+#define IPTS_SPEC_DEVICE_H -+ -+#include -+#include -+ -+/* -+ * The amount of buffers that IPTS can use for data transfer. -+ */ -+#define IPTS_BUFFERS 16 -+ -+/* -+ * The buffer ID that is used for HID2ME feedback -+ */ -+#define IPTS_HID2ME_BUFFER IPTS_BUFFERS -+ -+/** -+ * enum ipts_command - Commands that can be sent to the IPTS hardware. -+ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. -+ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. -+ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. -+ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. -+ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. -+ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. -+ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. -+ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. -+ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. -+ */ -+enum ipts_command_code { -+ IPTS_CMD_GET_DEVICE_INFO = 0x01, -+ IPTS_CMD_SET_MODE = 0x02, -+ IPTS_CMD_SET_MEM_WINDOW = 0x03, -+ IPTS_CMD_QUIESCE_IO = 0x04, -+ IPTS_CMD_READY_FOR_DATA = 0x05, -+ IPTS_CMD_FEEDBACK = 0x06, -+ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, -+ IPTS_CMD_RESET_SENSOR = 0x0B, -+ IPTS_CMD_GET_DESCRIPTOR = 0x0F, -+}; -+ -+/** -+ * enum ipts_status - Possible status codes returned by the IPTS device. -+ * @IPTS_STATUS_SUCCESS: Operation completed successfully. -+ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. -+ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. -+ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. -+ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. -+ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. -+ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. -+ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. -+ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. -+ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. -+ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. -+ * The host can ignore this error and attempt to continue. -+ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. -+ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. -+ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. -+ * @IPTS_STATUS_TIMEOUT: The operation timed out. -+ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. -+ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. -+ * Further progress is not possible. -+ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. -+ * The driver can attempt to continue. -+ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. -+ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. -+ */ -+enum ipts_status { -+ IPTS_STATUS_SUCCESS = 0x00, -+ IPTS_STATUS_INVALID_PARAMS = 0x01, -+ IPTS_STATUS_ACCESS_DENIED = 0x02, -+ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, -+ IPTS_STATUS_NOT_READY = 0x04, -+ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, -+ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, -+ IPTS_STATUS_OUT_OF_MEMORY = 0x07, -+ IPTS_STATUS_INTERNAL_ERROR = 0x08, -+ IPTS_STATUS_SENSOR_DISABLED = 0x09, -+ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, -+ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, -+ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, -+ IPTS_STATUS_RESET_FAILED = 0x0D, -+ IPTS_STATUS_TIMEOUT = 0x0E, -+ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, -+ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, -+ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, -+ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, -+ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, -+}; -+ -+/** -+ * struct ipts_command - Message that is sent to the device for calling a command. -+ * @cmd: The command that will be called. -+ * @payload: Payload containing parameters for the called command. -+ */ -+struct ipts_command { -+ enum ipts_command_code cmd; -+ u8 payload[320]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_command) == 324); -+ -+/** -+ * enum ipts_mode - Configures what data the device produces and how its sent. -+ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. -+ * Older devices will return singletouch data in this mode. -+ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. -+ * Older devices will return multitouch data in this mode. -+ */ -+enum ipts_mode { -+ IPTS_MODE_EVENT = 0x00, -+ IPTS_MODE_POLL = 0x01, -+}; -+ -+/** -+ * struct ipts_set_mode - Payload for the SET_MODE command. -+ * @mode: Changes the mode that IPTS will operate in. -+ */ -+struct ipts_set_mode { -+ enum ipts_mode mode; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_set_mode) == 16); -+ -+#define IPTS_WORKQUEUE_SIZE 8192 -+#define IPTS_WORKQUEUE_ITEM_SIZE 16 -+ -+/** -+ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. -+ * @data_addr_lower: Lower 32 bits of the data buffer addresses. -+ * @data_addr_upper: Upper 32 bits of the data buffer addresses. -+ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. -+ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. -+ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. -+ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. -+ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. -+ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. -+ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. -+ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. -+ * @hid2me_size: Size of the hid2me feedback buffer. -+ * @workqueue_item_size: Magic value. Must be 16. -+ * @workqueue_size: Magic value. Must be 8192. -+ * -+ * The workqueue related items in this struct are required for using -+ * GuC submission with binary processing firmware. Since this driver does -+ * not use GuC submission and instead exports raw data to userspace, these -+ * items are not actually used, but they need to be allocated and passed -+ * to the device, otherwise initialization will fail. -+ */ -+struct ipts_mem_window { -+ u32 data_addr_lower[IPTS_BUFFERS]; -+ u32 data_addr_upper[IPTS_BUFFERS]; -+ u32 workqueue_addr_lower; -+ u32 workqueue_addr_upper; -+ u32 doorbell_addr_lower; -+ u32 doorbell_addr_upper; -+ u32 feedback_addr_lower[IPTS_BUFFERS]; -+ u32 feedback_addr_upper[IPTS_BUFFERS]; -+ u32 hid2me_addr_lower; -+ u32 hid2me_addr_upper; -+ u32 hid2me_size; -+ u8 reserved1; -+ u8 workqueue_item_size; -+ u16 workqueue_size; -+ u8 reserved[32]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_mem_window) == 320); -+ -+/** -+ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. -+ */ -+struct ipts_quiesce_io { -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_quiesce_io) == 12); -+ -+/** -+ * struct ipts_feedback - Payload for the FEEDBACK command. -+ * @buffer: The buffer that the device should refill. -+ */ -+struct ipts_feedback { -+ u32 buffer; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_feedback) == 16); -+ -+/** -+ * enum ipts_reset_type - Possible ways of resetting the device. -+ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. -+ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. -+ */ -+enum ipts_reset_type { -+ IPTS_RESET_TYPE_HARD = 0x00, -+ IPTS_RESET_TYPE_SOFT = 0x01, -+}; -+ -+/** -+ * struct ipts_reset - Payload for the RESET_SENSOR command. -+ * @type: How the device should get reset. -+ */ -+struct ipts_reset_sensor { -+ enum ipts_reset_type type; -+ u8 reserved[4]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_reset_sensor) == 8); -+ -+/** -+ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. -+ * @addr_lower: The lower 32 bits of the descriptor buffer address. -+ * @addr_upper: The upper 32 bits of the descriptor buffer address. -+ * @magic: A magic value. Must be 8. -+ */ -+struct ipts_get_descriptor { -+ u32 addr_lower; -+ u32 addr_upper; -+ u32 magic; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_get_descriptor) == 24); -+ -+/* -+ * The type of a response is indicated by a -+ * command code, with the most significant bit flipped to 1. -+ */ -+#define IPTS_RSP_BIT BIT(31) -+ -+/** -+ * struct ipts_response - Data returned from the device in response to a command. -+ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). -+ * @status: The return code of the command. -+ * @payload: The data that was produced by the command. -+ */ -+struct ipts_response { -+ enum ipts_command_code cmd; -+ enum ipts_status status; -+ u8 payload[80]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_response) == 88); -+ -+/** -+ * struct ipts_device_info - Vendor information of the IPTS device. -+ * @vendor: Vendor ID of this device. -+ * @product: Product ID of this device. -+ * @hw_version: Hardware revision of this device. -+ * @fw_version: Firmware revision of this device. -+ * @data_size: Requested size for a data buffer. -+ * @feedback_size: Requested size for a feedback buffer. -+ * @mode: Mode that the device currently operates in. -+ * @max_contacts: Maximum amount of concurrent touches the sensor can process. -+ * @sensor_min_eds: The minimum EDS version supported by the sensor. -+ * @sensor_max_eds: The maximum EDS version supported by the sensor. -+ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. -+ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. -+ * @intf_eds: The EDS version implemented by the interface between ME and host. -+ */ -+struct ipts_device_info { -+ u16 vendor; -+ u16 product; -+ u32 hw_version; -+ u32 fw_version; -+ u32 data_size; -+ u32 feedback_size; -+ enum ipts_mode mode; -+ u8 max_contacts; -+ u8 reserved1[3]; -+ u8 sensor_min_eds; -+ u8 sensor_maj_eds; -+ u8 me_min_eds; -+ u8 me_maj_eds; -+ u8 intf_eds; -+ u8 reserved2[11]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_device_info) == 44); -+ -+#endif /* IPTS_SPEC_DEVICE_H */ -diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h -new file mode 100644 -index 000000000000..5a58d4a0a610 ---- /dev/null -+++ b/drivers/hid/ipts/spec-hid.h -@@ -0,0 +1,34 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_HID_H -+#define IPTS_SPEC_HID_H -+ -+#include -+#include -+ -+/* -+ * Made-up type for passing raw IPTS data in a HID report. -+ */ -+#define IPTS_HID_FRAME_TYPE_RAW 0xEE -+ -+/** -+ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. -+ * @size: Size of the data inside the report, including this header. -+ * @type: What type of data does this report contain. -+ */ -+struct ipts_hid_header { -+ u32 size; -+ u8 reserved1; -+ u8 type; -+ u8 reserved2; -+ u8 data[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_hid_header) == 7); -+ -+#endif /* IPTS_SPEC_HID_H */ -diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c -new file mode 100644 -index 000000000000..355e92bea26f ---- /dev/null -+++ b/drivers/hid/ipts/thread.c -@@ -0,0 +1,84 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "thread.h" -+ -+bool ipts_thread_should_stop(struct ipts_thread *thread) -+{ -+ if (!thread) -+ return false; -+ -+ return READ_ONCE(thread->should_stop); -+} -+ -+static int ipts_thread_runner(void *data) -+{ -+ int ret = 0; -+ struct ipts_thread *thread = data; -+ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!thread->threadfn) -+ return -EFAULT; -+ -+ ret = thread->threadfn(thread); -+ complete_all(&thread->done); -+ -+ return ret; -+} -+ -+int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), -+ void *data, const char *name) -+{ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!threadfn) -+ return -EFAULT; -+ -+ init_completion(&thread->done); -+ -+ thread->data = data; -+ thread->should_stop = false; -+ thread->threadfn = threadfn; -+ -+ thread->thread = kthread_run(ipts_thread_runner, thread, name); -+ return PTR_ERR_OR_ZERO(thread->thread); -+} -+ -+int ipts_thread_stop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!thread->thread) -+ return 0; -+ -+ WRITE_ONCE(thread->should_stop, true); -+ -+ /* -+ * Make sure that the write has gone through before waiting. -+ */ -+ wmb(); -+ -+ wait_for_completion(&thread->done); -+ ret = kthread_stop(thread->thread); -+ -+ thread->thread = NULL; -+ thread->data = NULL; -+ thread->threadfn = NULL; -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h -new file mode 100644 -index 000000000000..1f966b8b32c4 ---- /dev/null -+++ b/drivers/hid/ipts/thread.h -@@ -0,0 +1,59 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_THREAD_H -+#define IPTS_THREAD_H -+ -+#include -+#include -+#include -+ -+/* -+ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible -+ * to issue MEI commands from that thread while it shuts itself down. By using a custom -+ * boolean variable and a completion object, we can call kthread_stop only when the thread -+ * already finished all of its work and has returned. -+ */ -+struct ipts_thread { -+ struct task_struct *thread; -+ -+ bool should_stop; -+ struct completion done; -+ -+ void *data; -+ int (*threadfn)(struct ipts_thread *thread); -+}; -+ -+/** -+ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. -+ * @thread: The current thread. -+ * -+ * Returns: true if the thread should stop, false if not. -+ */ -+bool ipts_thread_should_stop(struct ipts_thread *thread); -+ -+/** -+ * ipts_thread_start() - Starts an IPTS thread. -+ * @thread: The thread to initialize and start. -+ * @threadfn: The function to execute. -+ * @data: An argument that will be passed to threadfn. -+ * @name: The name of the new thread. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), -+ void *data, const char name[]); -+ -+/** -+ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. -+ * @thread: The thread that should stop. -+ * -+ * Returns: The return value of the thread function. -+ */ -+int ipts_thread_stop(struct ipts_thread *thread); -+ -+#endif /* IPTS_THREAD_H */ --- -2.44.0 - -From e5b4ea8a015bee22023bb5c8fb6dd8b708bff7d5 Mon Sep 17 00:00:00 2001 -From: Jasmin Huber -Date: Mon, 15 Apr 2024 10:22:55 +0200 -Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile - with -Wmissing-prototypes. - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/hid/ipts/eds1.c | 1 + - drivers/hid/ipts/eds2.c | 1 + - drivers/hid/ipts/receiver.c | 1 + - 3 files changed, 3 insertions(+) - -diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c -index ecbb3a8bdaf6..7b9f54388a9f 100644 ---- a/drivers/hid/ipts/eds1.c -+++ b/drivers/hid/ipts/eds1.c -@@ -14,6 +14,7 @@ - #include "context.h" - #include "control.h" - #include "desc.h" -+#include "eds1.h" - #include "spec-device.h" - - int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c -index 198dc65d7887..639940794615 100644 ---- a/drivers/hid/ipts/eds2.c -+++ b/drivers/hid/ipts/eds2.c -@@ -15,6 +15,7 @@ - #include "context.h" - #include "control.h" - #include "desc.h" -+#include "eds2.h" - #include "spec-data.h" - - int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -index ef66c3c9db80..977724c728c3 100644 ---- a/drivers/hid/ipts/receiver.c -+++ b/drivers/hid/ipts/receiver.c -@@ -16,6 +16,7 @@ - #include "context.h" - #include "control.h" - #include "hid.h" -+#include "receiver.h" - #include "resources.h" - #include "spec-device.h" - #include "thread.h" --- -2.44.0 - diff --git a/patches/6.8/0005-ithc.patch b/patches/6.8/0005-ithc.patch deleted file mode 100644 index f9722e9c01..0000000000 --- a/patches/6.8/0005-ithc.patch +++ /dev/null @@ -1,4340 +0,0 @@ -From 619b488e58367467f52d636b5182ff2134df68c0 Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Sun, 11 Dec 2022 12:03:38 +0100 -Subject: [PATCH] iommu: intel: Disable source id verification for ITHC - -Signed-off-by: Dorian Stoll -Patchset: ithc ---- - drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 566297bc87dd..a8cd8f12d593 100644 ---- a/drivers/iommu/intel/irq_remapping.c -+++ b/drivers/iommu/intel/irq_remapping.c -@@ -386,6 +386,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) - data.busmatch_count = 0; - pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); - -+ /* -+ * The Intel Touch Host Controller is at 00:10.6, but for some reason -+ * the MSI interrupts have request id 01:05.0. -+ * Disable id verification to work around this. -+ * FIXME Find proper fix or turn this into a quirk. -+ */ -+ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { -+ switch(dev->device) { -+ case 0x98d0: case 0x98d1: // LKF -+ case 0xa0d0: case 0xa0d1: // TGL LP -+ case 0x43d0: case 0x43d1: // TGL H -+ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); -+ return 0; -+ } -+ } -+ - /* - * DMA alias provides us with a PCI device and alias. The only case - * where the it will return an alias on a different bus than the --- -2.44.0 - -From ee5106b4069dd150a323dce8bce7879d2b27ed0b Mon Sep 17 00:00:00 2001 -From: quo -Date: Sun, 11 Dec 2022 12:10:54 +0100 -Subject: [PATCH] hid: Add support for Intel Touch Host Controller - -Based on quo/ithc-linux@0b8b45d - -Signed-off-by: Dorian Stoll -Patchset: ithc ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 1 + - drivers/hid/ithc/Kbuild | 6 + - drivers/hid/ithc/Kconfig | 12 + - drivers/hid/ithc/ithc-debug.c | 130 ++++++ - drivers/hid/ithc/ithc-dma.c | 373 +++++++++++++++++ - drivers/hid/ithc/ithc-dma.h | 69 ++++ - drivers/hid/ithc/ithc-main.c | 728 ++++++++++++++++++++++++++++++++++ - drivers/hid/ithc/ithc-regs.c | 96 +++++ - drivers/hid/ithc/ithc-regs.h | 189 +++++++++ - drivers/hid/ithc/ithc.h | 67 ++++ - 11 files changed, 1673 insertions(+) - create mode 100644 drivers/hid/ithc/Kbuild - create mode 100644 drivers/hid/ithc/Kconfig - create mode 100644 drivers/hid/ithc/ithc-debug.c - create mode 100644 drivers/hid/ithc/ithc-dma.c - create mode 100644 drivers/hid/ithc/ithc-dma.h - create mode 100644 drivers/hid/ithc/ithc-main.c - create mode 100644 drivers/hid/ithc/ithc-regs.c - create mode 100644 drivers/hid/ithc/ithc-regs.h - create mode 100644 drivers/hid/ithc/ithc.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index a263e49b2ae2..03f0f5af289a 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1353,4 +1353,6 @@ source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/ipts/Kconfig" - -+source "drivers/hid/ithc/Kconfig" -+ - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index f4bad1b8d813..d32c194400ae 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - - obj-$(CONFIG_HID_IPTS) += ipts/ -+obj-$(CONFIG_HID_ITHC) += ithc/ -diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild -new file mode 100644 -index 000000000000..aea83f2ac07b ---- /dev/null -+++ b/drivers/hid/ithc/Kbuild -@@ -0,0 +1,6 @@ -+obj-$(CONFIG_HID_ITHC) := ithc.o -+ -+ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-debug.o -+ -+ccflags-y := -std=gnu11 -Wno-declaration-after-statement -+ -diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig -new file mode 100644 -index 000000000000..ede713023609 ---- /dev/null -+++ b/drivers/hid/ithc/Kconfig -@@ -0,0 +1,12 @@ -+config HID_ITHC -+ tristate "Intel Touch Host Controller" -+ depends on PCI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Touch Host Controller (ITHC / IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ithc. -diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c -new file mode 100644 -index 000000000000..1f1f1e33f2e5 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.c -@@ -0,0 +1,130 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+void ithc_log_regs(struct ithc *ithc) -+{ -+ if (!ithc->prev_regs) -+ return; -+ u32 __iomem *cur = (__iomem void *)ithc->regs; -+ u32 *prev = (void *)ithc->prev_regs; -+ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { -+ u32 x = readl(cur + i); -+ if (x != prev[i]) { -+ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); -+ prev[i] = x; -+ } -+ } -+} -+ -+static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, -+ loff_t *offset) -+{ -+ // Debug commands consist of a single letter followed by a list of numbers (decimal or -+ // hexadecimal, space-separated). -+ struct ithc *ithc = file_inode(f)->i_private; -+ char cmd[256]; -+ if (!ithc || !ithc->pci) -+ return -ENODEV; -+ if (!len) -+ return -EINVAL; -+ if (len >= sizeof(cmd)) -+ return -EINVAL; -+ if (copy_from_user(cmd, buf, len)) -+ return -EFAULT; -+ cmd[len] = 0; -+ if (cmd[len-1] == '\n') -+ cmd[len-1] = 0; -+ pci_info(ithc->pci, "debug command: %s\n", cmd); -+ -+ // Parse the list of arguments into a u32 array. -+ u32 n = 0; -+ const char *s = cmd + 1; -+ u32 a[32]; -+ while (*s && *s != '\n') { -+ if (n >= ARRAY_SIZE(a)) -+ return -EINVAL; -+ if (*s++ != ' ') -+ return -EINVAL; -+ char *e; -+ a[n++] = simple_strtoul(s, &e, 0); -+ if (e == s) -+ return -EINVAL; -+ s = e; -+ } -+ ithc_log_regs(ithc); -+ -+ // Execute the command. -+ switch (cmd[0]) { -+ case 'x': // reset -+ ithc_reset(ithc); -+ break; -+ case 'w': // write register: offset mask value -+ if (n != 3 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", -+ a[0], a[2], a[1]); -+ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); -+ break; -+ case 'r': // read register: offset -+ if (n != 1 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], -+ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); -+ break; -+ case 's': // spi command: cmd offset len data... -+ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ // set touch cfg: s 6 12 4 XX -+ if (n < 3 || a[2] > (n - 3) * 4) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); -+ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) -+ for (u32 i = 0; i < (a[2] + 3) / 4; i++) -+ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); -+ break; -+ case 'd': // dma command: cmd len data... -+ // get report descriptor: d 7 8 0 0 -+ // enable multitouch: d 3 2 0x0105 -+ if (n < 2 || a[1] > (n - 2) * 4) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]); -+ if (ithc_dma_tx(ithc, a[0], a[1], a + 2)) -+ pci_err(ithc->pci, "dma tx failed\n"); -+ break; -+ default: -+ return -EINVAL; -+ } -+ ithc_log_regs(ithc); -+ return len; -+} -+ -+static const struct file_operations ithc_debugfops_cmd = { -+ .owner = THIS_MODULE, -+ .write = ithc_debugfs_cmd_write, -+}; -+ -+static void ithc_debugfs_devres_release(struct device *dev, void *res) -+{ -+ struct dentry **dbgm = res; -+ if (*dbgm) -+ debugfs_remove_recursive(*dbgm); -+} -+ -+int ithc_debug_init(struct ithc *ithc) -+{ -+ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); -+ if (!dbgm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, dbgm); -+ struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL); -+ if (IS_ERR(dbg)) -+ return PTR_ERR(dbg); -+ *dbgm = dbg; -+ -+ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); -+ if (IS_ERR(cmd)) -+ return PTR_ERR(cmd); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c -new file mode 100644 -index 000000000000..ffb8689b8a78 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.c -@@ -0,0 +1,373 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. -+// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. -+// This allows each data buffer to consist of multiple non-contiguous blocks of memory. -+ -+static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, -+ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) -+{ -+ p->num_pages = num_pages; -+ p->dir = dir; -+ // We allocate enough space to have one PRD per data buffer page, however if the data -+ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so -+ // some will remain unused (which is fine). -+ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); -+ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); -+ if (!p->addr) -+ return -ENOMEM; -+ if (p->dma_addr & (PAGE_SIZE - 1)) -+ return -EFAULT; -+ return 0; -+} -+ -+// Devres managed sg_table wrapper. -+struct ithc_sg_table { -+ void *addr; -+ struct sg_table sgt; -+ enum dma_data_direction dir; -+}; -+static void ithc_dma_sgtable_free(struct sg_table *sgt) -+{ -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_sg(sgt, sg, i) { -+ struct page *p = sg_page(sg); -+ if (p) -+ __free_page(p); -+ } -+ sg_free_table(sgt); -+} -+static void ithc_dma_data_devres_release(struct device *dev, void *res) -+{ -+ struct ithc_sg_table *sgt = res; -+ if (sgt->addr) -+ vunmap(sgt->addr); -+ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); -+ ithc_dma_sgtable_free(&sgt->sgt); -+} -+ -+static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b) -+{ -+ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be -+ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). -+ // We could use dma_alloc_noncontiguous(), however this still always allocates a single -+ // DMA mapped segment, which is more restrictive than what we need. -+ // Instead we use an sg_table of individually allocated pages. -+ struct page *pages[16]; -+ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) -+ return -EINVAL; -+ b->active_idx = -1; -+ struct ithc_sg_table *sgt = devres_alloc( -+ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); -+ if (!sgt) -+ return -ENOMEM; -+ sgt->dir = prds->dir; -+ -+ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { -+ struct scatterlist *sg; -+ int i; -+ bool ok = true; -+ for_each_sgtable_sg(&sgt->sgt, sg, i) { -+ // NOTE: don't need __GFP_DMA for PCI DMA -+ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); -+ if (!p) { -+ ok = false; -+ break; -+ } -+ sg_set_page(sg, p, PAGE_SIZE, 0); -+ } -+ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { -+ devres_add(&ithc->pci->dev, sgt); -+ b->sgt = &sgt->sgt; -+ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); -+ if (!b->addr) -+ return -ENOMEM; -+ return 0; -+ } -+ ithc_dma_sgtable_free(&sgt->sgt); -+ } -+ devres_free(sgt); -+ return -ENOMEM; -+} -+ -+static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Give a buffer to the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ if (b->active_idx >= 0) { -+ pci_err(ithc->pci, "buffer already active\n"); -+ return -EINVAL; -+ } -+ b->active_idx = idx; -+ if (prds->dir == DMA_TO_DEVICE) { -+ // TX buffer: Caller should have already filled the data buffer, so just fill -+ // the PRD and flush. -+ // (TODO: Support multi-page TX buffers. So far no device seems to use or need -+ // these though.) -+ if (b->data_size > PAGE_SIZE) -+ return -EINVAL; -+ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; -+ prd->size = b->data_size | PRD_FLAG_END; -+ flush_kernel_vmap_range(b->addr, b->data_size); -+ } else if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Reset PRDs. -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ prd->addr = sg_dma_address(sg) >> 10; -+ prd->size = sg_dma_len(sg); -+ prd++; -+ } -+ prd[-1].size |= PRD_FLAG_END; -+ } -+ dma_wmb(); // for the prds -+ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Take a buffer from the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ // This is purely a sanity check. We don't strictly need the idx parameter for this -+ // function, because it should always be the same as active_idx, unless we have a bug. -+ if (b->active_idx != idx) { -+ pci_err(ithc->pci, "wrong buffer index\n"); -+ return -EINVAL; -+ } -+ b->active_idx = -1; -+ if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Calculate actual received data size from PRDs. -+ dma_rmb(); // for the prds -+ b->data_size = 0; -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ unsigned int size = prd->size; -+ b->data_size += size & PRD_SIZE_MASK; -+ if (size & PRD_FLAG_END) -+ break; -+ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { -+ pci_err(ithc->pci, "truncated prd\n"); -+ break; -+ } -+ prd++; -+ } -+ invalidate_kernel_vmap_range(b->addr, b->data_size); -+ } -+ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_init(&rx->mutex); -+ -+ // Allocate buffers. -+ u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes); -+ unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", -+ NUM_RX_BUF, buf_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); -+ -+ // Init registers. -+ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); -+ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); -+ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); -+ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); -+ u8 head = readb(&ithc->regs->dma_rx[channel].head); -+ if (head) { -+ pci_err(ithc->pci, "head is nonzero (%u)\n", head); -+ return -EIO; -+ } -+ -+ // Init buffers. -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); -+ -+ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); -+ return 0; -+} -+ -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) -+{ -+ bitsb_set(&ithc->regs->dma_rx[channel].control, -+ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, -+ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); -+} -+ -+int ithc_dma_tx_init(struct ithc *ithc) -+{ -+ struct ithc_dma_tx *tx = &ithc->dma_tx; -+ mutex_init(&tx->mutex); -+ -+ // Allocate buffers. -+ tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes); -+ unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", -+ tx->max_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); -+ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); -+ -+ // Init registers. -+ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); -+ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); -+ -+ // Init buffers. -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ return 0; -+} -+ -+static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data, -+ u8 channel, u8 buf) -+{ -+ if (buf >= NUM_RX_BUF) { -+ pci_err(ithc->pci, "invalid dma ringbuffer index\n"); -+ return -EINVAL; -+ } -+ u32 len = data->data_size; -+ struct ithc_dma_rx_header *hdr = data->addr; -+ u8 *hiddata = (void *)(hdr + 1); -+ if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) { -+ // The THC sends a reset request when we need to reinitialize the device. -+ // This usually only happens if we send an invalid command or put the device -+ // in a bad state. -+ CHECK(ithc_reset, ithc); -+ } else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) { -+ if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { -+ // When the CPU enters a low power state during DMA, we can get truncated -+ // messages. For Surface devices, this will typically be a single touch -+ // report that is only 1 byte, or a multitouch report that is 257 bytes. -+ // See also ithc_set_active(). -+ } else { -+ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n", -+ channel, buf, len, hdr->code, hdr->data_size); -+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -+ hdr, min(len, 0x400u), 0); -+ } -+ } else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) { -+ // Response to a 'get report descriptor' request. -+ // The actual descriptor is preceded by 8 nul bytes. -+ CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8); -+ WRITE_ONCE(ithc->hid_parse_done, true); -+ wake_up(&ithc->wait_hid_parse); -+ } else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { -+ // Standard HID input report containing touch data. -+ CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1); -+ } else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) { -+ // Response to a 'get feature' request. -+ bool done = false; -+ mutex_lock(&ithc->hid_get_feature_mutex); -+ if (ithc->hid_get_feature_buf) { -+ if (hdr->data_size < ithc->hid_get_feature_size) -+ ithc->hid_get_feature_size = hdr->data_size; -+ memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size); -+ ithc->hid_get_feature_buf = NULL; -+ done = true; -+ } -+ mutex_unlock(&ithc->hid_get_feature_mutex); -+ if (done) { -+ wake_up(&ithc->wait_hid_get_feature); -+ } else { -+ // Received data without a matching request, or the request already -+ // timed out. (XXX What's the correct thing to do here?) -+ CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT, -+ hiddata, hdr->data_size, 1); -+ } -+ } else { -+ pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n", -+ channel, buf, len, hdr->code); -+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -+ hdr, min(len, 0x400u), 0); -+ } -+ return 0; -+} -+ -+static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) -+{ -+ // Process all filled RX buffers from the ringbuffer. -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ unsigned int n = rx->num_received; -+ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); -+ while (1) { -+ u8 tail = n % NUM_RX_BUF; -+ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); -+ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); -+ // ringbuffer is full if tail_wrap == head_wrap -+ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG -+ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) -+ return 0; -+ -+ // take the buffer that the device just filled -+ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); -+ rx->num_received = ++n; -+ -+ // process data -+ CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail); -+ -+ // give the buffer back to the device -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); -+ } -+} -+int ithc_dma_rx(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_lock(&rx->mutex); -+ int ret = ithc_dma_rx_unlocked(ithc, channel); -+ mutex_unlock(&rx->mutex); -+ return ret; -+} -+ -+static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) -+{ -+ ithc_set_active(ithc, 100 * USEC_PER_MSEC); -+ -+ // Send a single TX buffer to the THC. -+ pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize); -+ struct ithc_dma_tx_header *hdr; -+ // Data must be padded to next 4-byte boundary. -+ u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0; -+ unsigned int fullsize = sizeof(*hdr) + datasize + padding; -+ if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE) -+ return -EINVAL; -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ -+ // Fill the TX buffer with header and data. -+ ithc->dma_tx.buf.data_size = fullsize; -+ hdr = ithc->dma_tx.buf.addr; -+ hdr->code = cmdcode; -+ hdr->data_size = datasize; -+ u8 *dest = (void *)(hdr + 1); -+ memcpy(dest, data, datasize); -+ dest += datasize; -+ for (u8 p = 0; p < padding; p++) -+ *dest++ = 0; -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ -+ // Let the THC process the buffer. -+ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); -+ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); -+ return 0; -+} -+int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) -+{ -+ mutex_lock(&ithc->dma_tx.mutex); -+ int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data); -+ mutex_unlock(&ithc->dma_tx.mutex); -+ return ret; -+} -+ -diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h -new file mode 100644 -index 000000000000..93652e4476bf ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.h -@@ -0,0 +1,69 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define PRD_SIZE_MASK 0xffffff -+#define PRD_FLAG_END 0x1000000 -+#define PRD_FLAG_SUCCESS 0x2000000 -+#define PRD_FLAG_ERROR 0x4000000 -+ -+struct ithc_phys_region_desc { -+ u64 addr; // physical addr/1024 -+ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds -+ u32 unused; -+}; -+ -+#define DMA_RX_CODE_INPUT_REPORT 3 -+#define DMA_RX_CODE_FEATURE_REPORT 4 -+#define DMA_RX_CODE_REPORT_DESCRIPTOR 5 -+#define DMA_RX_CODE_RESET 7 -+ -+struct ithc_dma_rx_header { -+ u32 code; -+ u32 data_size; -+ u32 _unknown[14]; -+}; -+ -+#define DMA_TX_CODE_SET_FEATURE 3 -+#define DMA_TX_CODE_GET_FEATURE 4 -+#define DMA_TX_CODE_OUTPUT_REPORT 5 -+#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7 -+ -+struct ithc_dma_tx_header { -+ u32 code; -+ u32 data_size; -+}; -+ -+struct ithc_dma_prd_buffer { -+ void *addr; -+ dma_addr_t dma_addr; -+ u32 size; -+ u32 num_pages; // per data buffer -+ enum dma_data_direction dir; -+}; -+ -+struct ithc_dma_data_buffer { -+ void *addr; -+ struct sg_table *sgt; -+ int active_idx; -+ u32 data_size; -+}; -+ -+struct ithc_dma_tx { -+ struct mutex mutex; -+ u32 max_size; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer buf; -+}; -+ -+struct ithc_dma_rx { -+ struct mutex mutex; -+ u32 num_received; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; -+}; -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel); -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); -+int ithc_dma_tx_init(struct ithc *ithc); -+int ithc_dma_rx(struct ithc *ithc, u8 channel); -+int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata); -+ -diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -new file mode 100644 -index 000000000000..87ed4aa70fda ---- /dev/null -+++ b/drivers/hid/ithc/ithc-main.c -@@ -0,0 +1,728 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+MODULE_DESCRIPTION("Intel Touch Host Controller driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+ -+// Lakefield -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 -+// Tiger Lake -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 -+// Alder Lake -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 -+// Raptor Lake -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 -+// Meteor Lake -+#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a -+ -+static const struct pci_device_id ithc_pci_tbl[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_MTL_PORT1) }, -+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_MTL_PORT2) }, -+ // XXX So far the THC seems to be the only Intel PCI device with PCI_CLASS_INPUT_PEN, -+ // so instead of the device list we could just do: -+ // { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .class = PCI_CLASS_INPUT_PEN, .class_mask = ~0, }, -+ {} -+}; -+MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); -+ -+// Module parameters -+ -+static bool ithc_use_polling = false; -+module_param_named(poll, ithc_use_polling, bool, 0); -+MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); -+ -+// Since all known devices seem to use only channel 1, by default we disable channel 0. -+static bool ithc_use_rx0 = false; -+module_param_named(rx0, ithc_use_rx0, bool, 0); -+MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); -+ -+static bool ithc_use_rx1 = true; -+module_param_named(rx1, ithc_use_rx1, bool, 0); -+MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); -+ -+// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering. -+static int ithc_dma_latency_us = 200; -+module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0); -+MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS"); -+ -+// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering. -+static unsigned int ithc_dma_early_us = 2000; -+module_param_named(dma_early_us, ithc_dma_early_us, uint, 0); -+MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)"); -+ -+static bool ithc_log_regs_enabled = false; -+module_param_named(logregs, ithc_log_regs_enabled, bool, 0); -+MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); -+ -+// Sysfs attributes -+ -+static bool ithc_is_config_valid(struct ithc *ithc) -+{ -+ return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC; -+} -+ -+static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ struct ithc *ithc = dev_get_drvdata(dev); -+ if (!ithc || !ithc_is_config_valid(ithc)) -+ return -ENODEV; -+ return sprintf(buf, "0x%04x", ithc->config.vendor_id); -+} -+static DEVICE_ATTR_RO(vendor); -+static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ struct ithc *ithc = dev_get_drvdata(dev); -+ if (!ithc || !ithc_is_config_valid(ithc)) -+ return -ENODEV; -+ return sprintf(buf, "0x%04x", ithc->config.product_id); -+} -+static DEVICE_ATTR_RO(product); -+static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ struct ithc *ithc = dev_get_drvdata(dev); -+ if (!ithc || !ithc_is_config_valid(ithc)) -+ return -ENODEV; -+ return sprintf(buf, "%u", ithc->config.revision); -+} -+static DEVICE_ATTR_RO(revision); -+static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ struct ithc *ithc = dev_get_drvdata(dev); -+ if (!ithc || !ithc_is_config_valid(ithc)) -+ return -ENODEV; -+ u32 v = ithc->config.fw_version; -+ return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff); -+} -+static DEVICE_ATTR_RO(fw_version); -+ -+static const struct attribute_group *ithc_attribute_groups[] = { -+ &(const struct attribute_group){ -+ .name = DEVNAME, -+ .attrs = (struct attribute *[]){ -+ &dev_attr_vendor.attr, -+ &dev_attr_product.attr, -+ &dev_attr_revision.attr, -+ &dev_attr_fw_version.attr, -+ NULL -+ }, -+ }, -+ NULL -+}; -+ -+// HID setup -+ -+static int ithc_hid_start(struct hid_device *hdev) { return 0; } -+static void ithc_hid_stop(struct hid_device *hdev) { } -+static int ithc_hid_open(struct hid_device *hdev) { return 0; } -+static void ithc_hid_close(struct hid_device *hdev) { } -+ -+static int ithc_hid_parse(struct hid_device *hdev) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ u64 val = 0; -+ WRITE_ONCE(ithc->hid_parse_done, false); -+ for (int retries = 0; ; retries++) { -+ CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val); -+ if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done), -+ msecs_to_jiffies(200))) -+ return 0; -+ if (retries > 5) { -+ pci_err(ithc->pci, "failed to read report descriptor\n"); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -+ } -+} -+ -+static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -+ size_t len, unsigned char rtype, int reqtype) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ if (!buf || !len) -+ return -EINVAL; -+ u32 code; -+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ code = DMA_TX_CODE_OUTPUT_REPORT; -+ } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ code = DMA_TX_CODE_SET_FEATURE; -+ } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -+ code = DMA_TX_CODE_GET_FEATURE; -+ } else { -+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -+ rtype, reqtype, reportnum); -+ return -EINVAL; -+ } -+ buf[0] = reportnum; -+ -+ if (reqtype == HID_REQ_GET_REPORT) { -+ // Prepare for response. -+ mutex_lock(&ithc->hid_get_feature_mutex); -+ ithc->hid_get_feature_buf = buf; -+ ithc->hid_get_feature_size = len; -+ mutex_unlock(&ithc->hid_get_feature_mutex); -+ -+ // Transmit 'get feature' request. -+ int r = CHECK(ithc_dma_tx, ithc, code, 1, buf); -+ if (!r) { -+ r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature, -+ !ithc->hid_get_feature_buf, msecs_to_jiffies(1000)); -+ if (!r) -+ r = -ETIMEDOUT; -+ else if (r < 0) -+ r = -EINTR; -+ else -+ r = 0; -+ } -+ -+ // If everything went ok, the buffer has been filled with the response data. -+ // Return the response size. -+ mutex_lock(&ithc->hid_get_feature_mutex); -+ ithc->hid_get_feature_buf = NULL; -+ if (!r) -+ r = ithc->hid_get_feature_size; -+ mutex_unlock(&ithc->hid_get_feature_mutex); -+ return r; -+ } -+ -+ // 'Set feature', or 'output report'. These don't have a response. -+ CHECK_RET(ithc_dma_tx, ithc, code, len, buf); -+ return 0; -+} -+ -+static struct hid_ll_driver ithc_ll_driver = { -+ .start = ithc_hid_start, -+ .stop = ithc_hid_stop, -+ .open = ithc_hid_open, -+ .close = ithc_hid_close, -+ .parse = ithc_hid_parse, -+ .raw_request = ithc_hid_raw_request, -+}; -+ -+static void ithc_hid_devres_release(struct device *dev, void *res) -+{ -+ struct hid_device **hidm = res; -+ if (*hidm) -+ hid_destroy_device(*hidm); -+} -+ -+static int ithc_hid_init(struct ithc *ithc) -+{ -+ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -+ if (!hidm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, hidm); -+ struct hid_device *hid = hid_allocate_device(); -+ if (IS_ERR(hid)) -+ return PTR_ERR(hid); -+ *hidm = hid; -+ -+ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -+ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -+ hid->ll_driver = &ithc_ll_driver; -+ hid->bus = BUS_PCI; -+ hid->vendor = ithc->config.vendor_id; -+ hid->product = ithc->config.product_id; -+ hid->version = 0x100; -+ hid->dev.parent = &ithc->pci->dev; -+ hid->driver_data = ithc; -+ -+ ithc->hid = hid; -+ return 0; -+} -+ -+// Interrupts/polling -+ -+static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t) -+{ -+ struct ithc *ithc = container_of(t, struct ithc, activity_start_timer); -+ ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC); -+ return HRTIMER_NORESTART; -+} -+ -+static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t) -+{ -+ struct ithc *ithc = container_of(t, struct ithc, activity_end_timer); -+ cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -+ return HRTIMER_NORESTART; -+} -+ -+void ithc_set_active(struct ithc *ithc, unsigned int duration_us) -+{ -+ if (ithc_dma_latency_us < 0) -+ return; -+ // When CPU usage is very low, the CPU can enter various low power states (C2-C10). -+ // This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be -+ // set when this happens. The amount of truncated messages can become very high, resulting -+ // in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency -+ // QoS request to prevent the CPU from entering low power states during touch interactions. -+ cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us); -+ hrtimer_start_range_ns(&ithc->activity_end_timer, -+ ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL); -+} -+ -+static int ithc_set_device_enabled(struct ithc *ithc, bool enable) -+{ -+ u32 x = ithc->config.touch_cfg = -+ (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 | -+ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0); -+ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -+ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); -+} -+ -+static void ithc_disable_interrupts(struct ithc *ithc) -+{ -+ writel(0, &ithc->regs->error_control); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); -+} -+ -+static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) -+{ -+ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA, -+ &ithc->regs->dma_rx[channel].status); -+} -+ -+static void ithc_clear_interrupts(struct ithc *ithc) -+{ -+ writel(0xffffffff, &ithc->regs->error_flags); -+ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, -+ &ithc->regs->dma_tx.status); -+} -+ -+static void ithc_process(struct ithc *ithc) -+{ -+ ithc_log_regs(ithc); -+ -+ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ -+ // Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer -+ ktime_t t = ktime_get(); -+ ktime_t dt = ktime_sub(t, ithc->last_rx_time); -+ if (rx0 || rx1) { -+ ithc->last_rx_time = t; -+ if (dt > ms_to_ktime(100)) { -+ ithc->cur_rx_seq_count = 0; -+ ithc->cur_rx_seq_errors = 0; -+ } -+ ithc->cur_rx_seq_count++; -+ if (!ithc_use_polling && ithc_dma_latency_us >= 0) { -+ // Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below) -+ cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -+ hrtimer_try_to_cancel(&ithc->activity_end_timer); -+ } -+ } -+ -+ // Read and clear error bits -+ u32 err = readl(&ithc->regs->error_flags); -+ if (err) { -+ writel(err, &ithc->regs->error_flags); -+ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "error flags: 0x%08x\n", err); -+ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) { -+ // Only log an error if we see a significant number of these errors. -+ ithc->cur_rx_seq_errors++; -+ if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10) -+ pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n", -+ ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt)); -+ } -+ } -+ -+ // Process DMA rx -+ if (ithc_use_rx0) { -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ if (rx0) -+ ithc_dma_rx(ithc, 0); -+ } -+ if (ithc_use_rx1) { -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ if (rx1) -+ ithc_dma_rx(ithc, 1); -+ } -+ -+ // Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT -+ if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) { -+ ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us)); -+ hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS); -+ } -+ -+ ithc_log_regs(ithc); -+} -+ -+static irqreturn_t ithc_interrupt_thread(int irq, void *arg) -+{ -+ struct ithc *ithc = arg; -+ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", -+ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), -+ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), -+ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), -+ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), -+ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); -+ ithc_process(ithc); -+ return IRQ_HANDLED; -+} -+ -+static int ithc_poll_thread(void *arg) -+{ -+ struct ithc *ithc = arg; -+ unsigned int sleep = 100; -+ while (!kthread_should_stop()) { -+ u32 n = ithc->dma_rx[1].num_received; -+ ithc_process(ithc); -+ // Decrease polling interval to 20ms if we received data, otherwise slowly -+ // increase it up to 200ms. -+ if (n != ithc->dma_rx[1].num_received) { -+ ithc_set_active(ithc, 100 * USEC_PER_MSEC); -+ sleep = 20; -+ } else { -+ sleep = min(200u, sleep + (sleep >> 4) + 1); -+ } -+ msleep_interruptible(sleep); -+ } -+ return 0; -+} -+ -+// Device initialization and shutdown -+ -+static void ithc_disable(struct ithc *ithc) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); -+ ithc_disable_interrupts(ithc); -+ ithc_clear_interrupts(ithc); -+} -+ -+static int ithc_init_device(struct ithc *ithc) -+{ -+ ithc_log_regs(ithc); -+ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; -+ ithc_disable(ithc); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); -+ -+ // Since we don't yet know which SPI config the device wants, use default speed and mode -+ // initially for reading config data. -+ ithc_set_spi_config(ithc, 10, 0); -+ -+ // Setting the following bit seems to make reading the config more reliable. -+ bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000); -+ -+ // If the device was previously enabled, wait a bit to make sure it's fully shut down. -+ if (was_enabled) -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ -+ // Take the touch device out of reset. -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -+ if (!waitl(ithc, &ithc->regs->state, 0xf, 2)) -+ break; -+ if (retries > 5) { -+ pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state)); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "invalid state, retrying reset\n"); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ if (msleep_interruptible(1000)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ // Waiting for the following status bit makes reading config much more reliable, -+ // however the official driver does not seem to do this... -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4); -+ -+ // Read configuration data. -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ memset(&ithc->config, 0, sizeof(ithc->config)); -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config); -+ u32 *p = (void *)&ithc->config; -+ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ if (ithc_is_config_valid(ithc)) -+ break; -+ if (retries > 10) { -+ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -+ ithc->config.device_id); -+ return -EIO; -+ } -+ pci_warn(ithc->pci, "failed to read config, retrying\n"); -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ // Apply SPI config and enable touch device. -+ CHECK_RET(ithc_set_spi_config, ithc, -+ DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config), -+ DEVCFG_SPI_MODE(ithc->config.spi_config)); -+ CHECK_RET(ithc_set_device_enabled, ithc, true); -+ ithc_log_regs(ithc); -+ return 0; -+} -+ -+int ithc_reset(struct ithc *ithc) -+{ -+ // FIXME This should probably do devres_release_group()+ithc_start(). -+ // But because this is called during DMA processing, that would have to be done -+ // asynchronously (schedule_work()?). And with extra locking? -+ pci_err(ithc->pci, "reset\n"); -+ CHECK(ithc_init_device, ithc); -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "reset completed\n"); -+ return 0; -+} -+ -+static void ithc_stop(void *res) -+{ -+ struct ithc *ithc = res; -+ pci_dbg(ithc->pci, "stopping\n"); -+ ithc_log_regs(ithc); -+ -+ if (ithc->poll_thread) -+ CHECK(kthread_stop, ithc->poll_thread); -+ if (ithc->irq >= 0) -+ disable_irq(ithc->irq); -+ CHECK(ithc_set_device_enabled, ithc, false); -+ ithc_disable(ithc); -+ hrtimer_cancel(&ithc->activity_start_timer); -+ hrtimer_cancel(&ithc->activity_end_timer); -+ cpu_latency_qos_remove_request(&ithc->activity_qos); -+ -+ // Clear DMA config. -+ for (unsigned int i = 0; i < 2; i++) { -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); -+ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); -+ writeb(0, &ithc->regs->dma_rx[i].num_bufs); -+ writeb(0, &ithc->regs->dma_rx[i].num_prds); -+ } -+ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); -+ writeb(0, &ithc->regs->dma_tx.num_prds); -+ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "stopped\n"); -+} -+ -+static void ithc_clear_drvdata(void *res) -+{ -+ struct pci_dev *pci = res; -+ pci_set_drvdata(pci, NULL); -+} -+ -+static int ithc_start(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "starting\n"); -+ if (pci_get_drvdata(pci)) { -+ pci_err(pci, "device already initialized\n"); -+ return -EINVAL; -+ } -+ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) -+ return -ENOMEM; -+ -+ // Allocate/init main driver struct. -+ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); -+ if (!ithc) -+ return -ENOMEM; -+ ithc->irq = -1; -+ ithc->pci = pci; -+ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); -+ init_waitqueue_head(&ithc->wait_hid_parse); -+ init_waitqueue_head(&ithc->wait_hid_get_feature); -+ mutex_init(&ithc->hid_get_feature_mutex); -+ pci_set_drvdata(pci, ithc); -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); -+ if (ithc_log_regs_enabled) -+ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); -+ -+ // PCI initialization. -+ CHECK_RET(pcim_enable_device, pci); -+ pci_set_master(pci); -+ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); -+ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); -+ CHECK_RET(pci_set_power_state, pci, PCI_D0); -+ ithc->regs = pcim_iomap_table(pci)[0]; -+ -+ // Allocate IRQ. -+ if (!ithc_use_polling) { -+ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); -+ ithc->irq = CHECK(pci_irq_vector, pci, 0); -+ if (ithc->irq < 0) -+ return ithc->irq; -+ } -+ -+ // Initialize THC and touch device. -+ CHECK_RET(ithc_init_device, ithc); -+ CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups); -+ if (ithc_use_rx0) -+ CHECK_RET(ithc_dma_rx_init, ithc, 0); -+ if (ithc_use_rx1) -+ CHECK_RET(ithc_dma_rx_init, ithc, 1); -+ CHECK_RET(ithc_dma_tx_init, ithc); -+ -+ cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -+ hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); -+ ithc->activity_start_timer.function = ithc_activity_start_timer_callback; -+ hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ ithc->activity_end_timer.function = ithc_activity_end_timer_callback; -+ -+ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are -+ // disabled BEFORE the buffers are freed. -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); -+ -+ CHECK_RET(ithc_hid_init, ithc); -+ -+ // Start polling/IRQ. -+ if (ithc_use_polling) { -+ pci_info(pci, "using polling instead of irq\n"); -+ // Use a thread instead of simple timer because we want to be able to sleep. -+ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); -+ if (IS_ERR(ithc->poll_thread)) { -+ int err = PTR_ERR(ithc->poll_thread); -+ ithc->poll_thread = NULL; -+ return err; -+ } -+ } else { -+ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, -+ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); -+ } -+ -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ -+ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, -+ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. -+ CHECK_RET(hid_add_device, ithc->hid); -+ -+ CHECK(ithc_debug_init, ithc); -+ -+ pci_dbg(pci, "started\n"); -+ return 0; -+} -+ -+static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) -+{ -+ pci_dbg(pci, "device probe\n"); -+ return ithc_start(pci); -+} -+ -+static void ithc_remove(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "device remove\n"); -+ // all cleanup is handled by devres -+} -+ -+// For suspend/resume, we just deinitialize and reinitialize everything. -+// TODO It might be cleaner to keep the HID device around, however we would then have to signal -+// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set -+// feature' requests. Hidraw does not seem to have a facility to do that. -+static int ithc_suspend(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm suspend\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_resume(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm resume\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_freeze(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm freeze\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_thaw(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm thaw\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_restore(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm restore\n"); -+ return ithc_start(pci); -+} -+ -+static struct pci_driver ithc_driver = { -+ .name = DEVNAME, -+ .id_table = ithc_pci_tbl, -+ .probe = ithc_probe, -+ .remove = ithc_remove, -+ .driver.pm = &(const struct dev_pm_ops) { -+ .suspend = ithc_suspend, -+ .resume = ithc_resume, -+ .freeze = ithc_freeze, -+ .thaw = ithc_thaw, -+ .restore = ithc_restore, -+ }, -+ //.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway -+}; -+ -+static int __init ithc_init(void) -+{ -+ return pci_register_driver(&ithc_driver); -+} -+ -+static void __exit ithc_exit(void) -+{ -+ pci_unregister_driver(&ithc_driver); -+} -+ -+module_init(ithc_init); -+module_exit(ithc_exit); -+ -diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c -new file mode 100644 -index 000000000000..e058721886e3 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.c -@@ -0,0 +1,96 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writel((readl(reg) & ~mask) | (val & mask), reg); -+} -+ -+void bitsb(__iomem u8 *reg, u8 mask, u8 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writeb((readb(reg) & ~mask) | (val & mask), reg); -+} -+ -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) -+{ -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ u32 x; -+ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) -+{ -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ u8 x; -+ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode) -+{ -+ pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode); -+ if (mode == 3) -+ mode = 2; -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff), -+ SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed)); -+ return 0; -+} -+ -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) -+{ -+ pci_dbg(ithc->pci, "SPI command %u, size %u, offset %u\n", command, size, offset); -+ if (size > sizeof(ithc->regs->spi_cmd.data)) -+ return -EINVAL; -+ -+ // Wait if the device is still busy. -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ // Clear result flags. -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ -+ // Init SPI command data. -+ writeb(command, &ithc->regs->spi_cmd.code); -+ writew(size, &ithc->regs->spi_cmd.size); -+ writel(offset, &ithc->regs->spi_cmd.offset); -+ u32 *p = data, n = (size + 3) / 4; -+ for (u32 i = 0; i < n; i++) -+ writel(p[i], &ithc->regs->spi_cmd.data[i]); -+ -+ // Start transmission. -+ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ -+ // Read response. -+ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) -+ return -EIO; -+ if (readw(&ithc->regs->spi_cmd.size) != size) -+ return -EMSGSIZE; -+ for (u32 i = 0; i < n; i++) -+ p[i] = readl(&ithc->regs->spi_cmd.data[i]); -+ -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h -new file mode 100644 -index 000000000000..d4007d9e2bac ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.h -@@ -0,0 +1,189 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define CONTROL_QUIESCE BIT(1) -+#define CONTROL_IS_QUIESCED BIT(2) -+#define CONTROL_NRESET BIT(3) -+#define CONTROL_READY BIT(29) -+ -+#define SPI_CONFIG_MODE(x) (((x) & 3) << 2) -+#define SPI_CONFIG_SPEED(x) (((x) & 7) << 4) -+#define SPI_CONFIG_UNKNOWN_18(x) (((x) & 3) << 18) -+#define SPI_CONFIG_SPEED2(x) (((x) & 0xf) << 20) // high bit = high speed mode? -+ -+#define ERROR_CONTROL_UNKNOWN_0 BIT(0) -+#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs -+#define ERROR_CONTROL_UNKNOWN_2 BIT(2) -+#define ERROR_CONTROL_UNKNOWN_3 BIT(3) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? -+#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs -+ -+#define ERROR_STATUS_DMA BIT(28) -+#define ERROR_STATUS_SPI BIT(30) -+ -+#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message -+#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) -+#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) -+#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) -+#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) -+#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) -+#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) -+ -+#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define SPI_CMD_CONTROL_IRQ BIT(1) -+ -+#define SPI_CMD_CODE_READ 4 -+#define SPI_CMD_CODE_WRITE 6 -+ -+#define SPI_CMD_STATUS_DONE BIT(0) -+#define SPI_CMD_STATUS_ERROR BIT(1) -+#define SPI_CMD_STATUS_BUSY BIT(3) -+ -+#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define DMA_TX_CONTROL_IRQ BIT(3) -+ -+#define DMA_TX_STATUS_DONE BIT(0) -+#define DMA_TX_STATUS_ERROR BIT(1) -+#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) -+#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? -+ -+#define DMA_RX_CONTROL_ENABLE BIT(0) -+#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_UNKNOWN_4 BIT(4) // rx0 only? -+#define DMA_RX_CONTROL_IRQ_DATA BIT(5) -+ -+#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? -+#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices -+ -+#define DMA_RX_WRAP_FLAG BIT(7) -+ -+#define DMA_RX_STATUS_ERROR BIT(3) -+#define DMA_RX_STATUS_UNKNOWN_4 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) -+#define DMA_RX_STATUS_HAVE_DATA BIT(5) -+#define DMA_RX_STATUS_ENABLED BIT(8) -+ -+// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. -+#define COUNTER_RESET BIT(31) -+ -+struct ithc_registers { -+ /* 0000 */ u32 _unknown_0000[1024]; -+ /* 1000 */ u32 _unknown_1000; -+ /* 1004 */ u32 _unknown_1004; -+ /* 1008 */ u32 control_bits; -+ /* 100c */ u32 _unknown_100c; -+ /* 1010 */ u32 spi_config; -+ /* 1014 */ u32 _unknown_1014[3]; -+ /* 1020 */ u32 error_control; -+ /* 1024 */ u32 error_status; // write to clear -+ /* 1028 */ u32 error_flags; // write to clear -+ /* 102c */ u32 _unknown_102c[5]; -+ struct { -+ /* 1040 */ u8 control; -+ /* 1041 */ u8 code; -+ /* 1042 */ u16 size; -+ /* 1044 */ u32 status; // write to clear -+ /* 1048 */ u32 offset; -+ /* 104c */ u32 data[16]; -+ /* 108c */ u32 _unknown_108c; -+ } spi_cmd; -+ struct { -+ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1098 */ u8 control; -+ /* 1099 */ u8 _unknown_1099; -+ /* 109a */ u8 _unknown_109a; -+ /* 109b */ u8 num_prds; -+ /* 109c */ u32 status; // write to clear -+ } dma_tx; -+ /* 10a0 */ u32 _unknown_10a0[7]; -+ /* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET -+ /* 10c0 */ u32 _unknown_10c0[8]; -+ /* 10e0 */ u32 _unknown_10e0_counters[3]; -+ /* 10ec */ u32 _unknown_10ec[5]; -+ struct { -+ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1108/1208 */ u8 num_bufs; -+ /* 1109/1209 */ u8 num_prds; -+ /* 110a/120a */ u16 _unknown_110a; -+ /* 110c/120c */ u8 control; -+ /* 110d/120d */ u8 head; -+ /* 110e/120e */ u8 tail; -+ /* 110f/120f */ u8 control2; -+ /* 1110/1210 */ u32 status; // write to clear -+ /* 1114/1214 */ u32 _unknown_1114; -+ /* 1118/1218 */ u64 _unknown_1118_guc_addr; -+ /* 1120/1220 */ u32 _unknown_1120_guc; -+ /* 1124/1224 */ u32 _unknown_1124_guc; -+ /* 1128/1228 */ u32 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related -+ /* 112c/122c */ u32 _unknown_112c; -+ /* 1130/1230 */ u64 _unknown_1130_guc_addr; -+ /* 1138/1238 */ u32 _unknown_1138_guc; -+ /* 113c/123c */ u32 _unknown_113c; -+ /* 1140/1240 */ u32 _unknown_1140_guc; -+ /* 1144/1244 */ u32 _unknown_1144[23]; -+ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; -+ /* 11b8/12b8 */ u32 _unknown_11b8[18]; -+ } dma_rx[2]; -+}; -+static_assert(sizeof(struct ithc_registers) == 0x1300); -+ -+#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) -+#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) -+ -+#define DEVCFG_TOUCH_MASK 0x3f -+#define DEVCFG_TOUCH_ENABLE BIT(0) -+#define DEVCFG_TOUCH_UNKNOWN_1 BIT(1) -+#define DEVCFG_TOUCH_UNKNOWN_2 BIT(2) -+#define DEVCFG_TOUCH_UNKNOWN_3 BIT(3) -+#define DEVCFG_TOUCH_UNKNOWN_4 BIT(4) -+#define DEVCFG_TOUCH_UNKNOWN_5 BIT(5) -+#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) -+ -+#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" -+ -+#define DEVCFG_SPI_MAX_FREQ(x) (((x) >> 1) & 0xf) // high bit = use high speed mode? -+#define DEVCFG_SPI_MODE(x) (((x) >> 6) & 3) -+#define DEVCFG_SPI_UNKNOWN_8(x) (((x) >> 8) & 0x3f) -+#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat -+#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) -+#define DEVCFG_SPI_UNKNOWN_25 BIT(25) -+#define DEVCFG_SPI_UNKNOWN_26 BIT(26) -+#define DEVCFG_SPI_UNKNOWN_27 BIT(27) -+#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this -+#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? -+ -+struct ithc_device_config { // (Example values are from an SP7+.) -+ u32 _unknown_00; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) -+ u32 _unknown_04; // 04 = 0x00000000 -+ u32 dma_buf_sizes; // 08 = 0x000a00ff -+ u32 touch_cfg; // 0c = 0x0000001c -+ u32 _unknown_10; // 10 = 0x0000001c -+ u32 device_id; // 14 = 0x43495424 = "$TIC" -+ u32 spi_config; // 18 = 0xfda00a2e -+ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. -+ u16 product_id; // 1e = 0x0c1a -+ u32 revision; // 20 = 0x00000001 -+ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) -+ u32 _unknown_28; // 28 = 0x00000000 -+ u32 fw_mode; // 2c = 0x00000000 (for fw update?) -+ u32 _unknown_30; // 30 = 0x00000000 -+ u32 _unknown_34; // 34 = 0x0404035e (u8,u8,u8,u8 = version?) -+ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) -+ u32 _unknown_3c; // 3c = 0x00000002 -+}; -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val); -+void bitsb(__iomem u8 *reg, u8 mask, u8 val); -+#define bitsl_set(reg, x) bitsl(reg, x, x) -+#define bitsb_set(reg, x) bitsb(reg, x, x) -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); -+int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode); -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); -+ -diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h -new file mode 100644 -index 000000000000..028e55a4ec53 ---- /dev/null -+++ b/drivers/hid/ithc/ithc.h -@@ -0,0 +1,67 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEVNAME "ithc" -+#define DEVFULLNAME "Intel Touch Host Controller" -+ -+#undef pr_fmt -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) -+#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) -+ -+#define NUM_RX_BUF 16 -+ -+struct ithc; -+ -+#include "ithc-regs.h" -+#include "ithc-dma.h" -+ -+struct ithc { -+ char phys[32]; -+ struct pci_dev *pci; -+ int irq; -+ struct task_struct *poll_thread; -+ -+ struct pm_qos_request activity_qos; -+ struct hrtimer activity_start_timer; -+ struct hrtimer activity_end_timer; -+ ktime_t last_rx_time; -+ unsigned int cur_rx_seq_count; -+ unsigned int cur_rx_seq_errors; -+ -+ struct hid_device *hid; -+ bool hid_parse_done; -+ wait_queue_head_t wait_hid_parse; -+ wait_queue_head_t wait_hid_get_feature; -+ struct mutex hid_get_feature_mutex; -+ void *hid_get_feature_buf; -+ size_t hid_get_feature_size; -+ -+ struct ithc_registers __iomem *regs; -+ struct ithc_registers *prev_regs; // for debugging -+ struct ithc_device_config config; -+ struct ithc_dma_rx dma_rx[2]; -+ struct ithc_dma_tx dma_tx; -+}; -+ -+int ithc_reset(struct ithc *ithc); -+void ithc_set_active(struct ithc *ithc, unsigned int duration_us); -+int ithc_debug_init(struct ithc *ithc); -+void ithc_log_regs(struct ithc *ithc); -+ --- -2.44.0 - -From 62697b8742afc950b55ed24d8ef2fca5834426b6 Mon Sep 17 00:00:00 2001 -From: quo -Date: Fri, 19 Apr 2024 22:11:09 +0200 -Subject: [PATCH] hid: ithc: Update from quo/ithc-linux - - - Added QuickSPI support for Surface Laptop Studio 2 - - Use Latency Tolerance Reporting instead of manual CPU latency adjustments - -Based on: https://github.com/quo/ithc-linux/commit/18afc6ffacd70b49fdee2eb1ab0a8acd159edb31 - -Signed-off-by: Dorian Stoll -Patchset: ithc ---- - drivers/hid/ithc/Kbuild | 2 +- - drivers/hid/ithc/ithc-debug.c | 33 +- - drivers/hid/ithc/ithc-debug.h | 7 + - drivers/hid/ithc/ithc-dma.c | 125 ++----- - drivers/hid/ithc/ithc-dma.h | 24 +- - drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ - drivers/hid/ithc/ithc-hid.h | 32 ++ - drivers/hid/ithc/ithc-legacy.c | 252 ++++++++++++++ - drivers/hid/ithc/ithc-legacy.h | 8 + - drivers/hid/ithc/ithc-main.c | 386 ++++----------------- - drivers/hid/ithc/ithc-quickspi.c | 578 +++++++++++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.h | 39 +++ - drivers/hid/ithc/ithc-regs.c | 72 +++- - drivers/hid/ithc/ithc-regs.h | 143 ++++---- - drivers/hid/ithc/ithc.h | 71 ++-- - 15 files changed, 1441 insertions(+), 538 deletions(-) - create mode 100644 drivers/hid/ithc/ithc-debug.h - create mode 100644 drivers/hid/ithc/ithc-hid.c - create mode 100644 drivers/hid/ithc/ithc-hid.h - create mode 100644 drivers/hid/ithc/ithc-legacy.c - create mode 100644 drivers/hid/ithc/ithc-legacy.h - create mode 100644 drivers/hid/ithc/ithc-quickspi.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.h - -diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild -index aea83f2ac07b..4937ba131297 100644 ---- a/drivers/hid/ithc/Kbuild -+++ b/drivers/hid/ithc/Kbuild -@@ -1,6 +1,6 @@ - obj-$(CONFIG_HID_ITHC) := ithc.o - --ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-debug.o -+ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o - - ccflags-y := -std=gnu11 -Wno-declaration-after-statement - -diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c -index 1f1f1e33f2e5..2d8c6afe9966 100644 ---- a/drivers/hid/ithc/ithc-debug.c -+++ b/drivers/hid/ithc/ithc-debug.c -@@ -85,10 +85,11 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si - case 'd': // dma command: cmd len data... - // get report descriptor: d 7 8 0 0 - // enable multitouch: d 3 2 0x0105 -- if (n < 2 || a[1] > (n - 2) * 4) -+ if (n < 1) - return -EINVAL; -- pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]); -- if (ithc_dma_tx(ithc, a[0], a[1], a + 2)) -+ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); -+ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; -+ if (ithc_dma_tx(ithc, &data)) - pci_err(ithc->pci, "dma tx failed\n"); - break; - default: -@@ -98,6 +99,23 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si - return len; - } - -+static struct dentry *dbg_dir; -+ -+void __init ithc_debug_init_module(void) -+{ -+ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); -+ if (IS_ERR(d)) -+ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); -+ else -+ dbg_dir = d; -+} -+ -+void __exit ithc_debug_exit_module(void) -+{ -+ debugfs_remove_recursive(dbg_dir); -+ dbg_dir = NULL; -+} -+ - static const struct file_operations ithc_debugfops_cmd = { - .owner = THIS_MODULE, - .write = ithc_debugfs_cmd_write, -@@ -106,17 +124,18 @@ static const struct file_operations ithc_debugfops_cmd = { - static void ithc_debugfs_devres_release(struct device *dev, void *res) - { - struct dentry **dbgm = res; -- if (*dbgm) -- debugfs_remove_recursive(*dbgm); -+ debugfs_remove_recursive(*dbgm); - } - --int ithc_debug_init(struct ithc *ithc) -+int ithc_debug_init_device(struct ithc *ithc) - { -+ if (!dbg_dir) -+ return -ENOENT; - struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); - if (!dbgm) - return -ENOMEM; - devres_add(&ithc->pci->dev, dbgm); -- struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL); -+ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); - if (IS_ERR(dbg)) - return PTR_ERR(dbg); - *dbgm = dbg; -diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h -new file mode 100644 -index 000000000000..38c53d916bdb ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.h -@@ -0,0 +1,7 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+void ithc_debug_init_module(void); -+void ithc_debug_exit_module(void); -+int ithc_debug_init_device(struct ithc *ithc); -+void ithc_log_regs(struct ithc *ithc); -+ -diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c -index ffb8689b8a78..bf4eab33062b 100644 ---- a/drivers/hid/ithc/ithc-dma.c -+++ b/drivers/hid/ithc/ithc-dma.c -@@ -173,10 +173,9 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel) - mutex_init(&rx->mutex); - - // Allocate buffers. -- u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes); -- unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; - pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", -- NUM_RX_BUF, buf_size, num_pages); -+ NUM_RX_BUF, ithc->max_rx_size, num_pages); - CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); - for (unsigned int i = 0; i < NUM_RX_BUF; i++) - CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); -@@ -214,10 +213,9 @@ int ithc_dma_tx_init(struct ithc *ithc) - mutex_init(&tx->mutex); - - // Allocate buffers. -- tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes); -- unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; - pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", -- tx->max_size, num_pages); -+ ithc->max_tx_size, num_pages); - CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); - CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); - -@@ -230,71 +228,6 @@ int ithc_dma_tx_init(struct ithc *ithc) - return 0; - } - --static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data, -- u8 channel, u8 buf) --{ -- if (buf >= NUM_RX_BUF) { -- pci_err(ithc->pci, "invalid dma ringbuffer index\n"); -- return -EINVAL; -- } -- u32 len = data->data_size; -- struct ithc_dma_rx_header *hdr = data->addr; -- u8 *hiddata = (void *)(hdr + 1); -- if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) { -- // The THC sends a reset request when we need to reinitialize the device. -- // This usually only happens if we send an invalid command or put the device -- // in a bad state. -- CHECK(ithc_reset, ithc); -- } else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) { -- if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { -- // When the CPU enters a low power state during DMA, we can get truncated -- // messages. For Surface devices, this will typically be a single touch -- // report that is only 1 byte, or a multitouch report that is 257 bytes. -- // See also ithc_set_active(). -- } else { -- pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n", -- channel, buf, len, hdr->code, hdr->data_size); -- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -- hdr, min(len, 0x400u), 0); -- } -- } else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) { -- // Response to a 'get report descriptor' request. -- // The actual descriptor is preceded by 8 nul bytes. -- CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8); -- WRITE_ONCE(ithc->hid_parse_done, true); -- wake_up(&ithc->wait_hid_parse); -- } else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { -- // Standard HID input report containing touch data. -- CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1); -- } else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) { -- // Response to a 'get feature' request. -- bool done = false; -- mutex_lock(&ithc->hid_get_feature_mutex); -- if (ithc->hid_get_feature_buf) { -- if (hdr->data_size < ithc->hid_get_feature_size) -- ithc->hid_get_feature_size = hdr->data_size; -- memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size); -- ithc->hid_get_feature_buf = NULL; -- done = true; -- } -- mutex_unlock(&ithc->hid_get_feature_mutex); -- if (done) { -- wake_up(&ithc->wait_hid_get_feature); -- } else { -- // Received data without a matching request, or the request already -- // timed out. (XXX What's the correct thing to do here?) -- CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT, -- hiddata, hdr->data_size, 1); -- } -- } else { -- pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n", -- channel, buf, len, hdr->code); -- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -- hdr, min(len, 0x400u), 0); -- } -- return 0; --} -- - static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) - { - // Process all filled RX buffers from the ringbuffer. -@@ -316,7 +249,16 @@ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) - rx->num_received = ++n; - - // process data -- CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail); -+ struct ithc_data d; -+ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) -+ (ithc, b->addr, b->data_size, &d) < 0) { -+ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", -+ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); -+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -+ b->addr, min(b->data_size, 0x400u), 0); -+ } else { -+ ithc_hid_process_data(ithc, &d); -+ } - - // give the buffer back to the device - CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); -@@ -331,31 +273,28 @@ int ithc_dma_rx(struct ithc *ithc, u8 channel) - return ret; - } - --static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) -+static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) - { -- ithc_set_active(ithc, 100 * USEC_PER_MSEC); -- - // Send a single TX buffer to the THC. -- pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize); -- struct ithc_dma_tx_header *hdr; -- // Data must be padded to next 4-byte boundary. -- u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0; -- unsigned int fullsize = sizeof(*hdr) + datasize + padding; -- if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE) -- return -EINVAL; -+ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); - CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); - - // Fill the TX buffer with header and data. -- ithc->dma_tx.buf.data_size = fullsize; -- hdr = ithc->dma_tx.buf.addr; -- hdr->code = cmdcode; -- hdr->data_size = datasize; -- u8 *dest = (void *)(hdr + 1); -- memcpy(dest, data, datasize); -- dest += datasize; -- for (u8 p = 0; p < padding; p++) -- *dest++ = 0; -+ ssize_t sz; -+ if (data->type == ITHC_DATA_RAW) { -+ sz = min(data->size, ithc->max_tx_size); -+ memcpy(ithc->dma_tx.buf.addr, data->data, sz); -+ } else { -+ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) -+ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); -+ } -+ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; - CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ if (sz < 0) { -+ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", -+ data->type, data->size, (int)sz); -+ return -EINVAL; -+ } - - // Let the THC process the buffer. - bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); -@@ -363,10 +302,10 @@ static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, vo - writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); - return 0; - } --int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) - { - mutex_lock(&ithc->dma_tx.mutex); -- int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data); -+ int ret = ithc_dma_tx_unlocked(ithc, data); - mutex_unlock(&ithc->dma_tx.mutex); - return ret; - } -diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h -index 93652e4476bf..1749a5819b3e 100644 ---- a/drivers/hid/ithc/ithc-dma.h -+++ b/drivers/hid/ithc/ithc-dma.h -@@ -11,27 +11,6 @@ struct ithc_phys_region_desc { - u32 unused; - }; - --#define DMA_RX_CODE_INPUT_REPORT 3 --#define DMA_RX_CODE_FEATURE_REPORT 4 --#define DMA_RX_CODE_REPORT_DESCRIPTOR 5 --#define DMA_RX_CODE_RESET 7 -- --struct ithc_dma_rx_header { -- u32 code; -- u32 data_size; -- u32 _unknown[14]; --}; -- --#define DMA_TX_CODE_SET_FEATURE 3 --#define DMA_TX_CODE_GET_FEATURE 4 --#define DMA_TX_CODE_OUTPUT_REPORT 5 --#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7 -- --struct ithc_dma_tx_header { -- u32 code; -- u32 data_size; --}; -- - struct ithc_dma_prd_buffer { - void *addr; - dma_addr_t dma_addr; -@@ -49,7 +28,6 @@ struct ithc_dma_data_buffer { - - struct ithc_dma_tx { - struct mutex mutex; -- u32 max_size; - struct ithc_dma_prd_buffer prds; - struct ithc_dma_data_buffer buf; - }; -@@ -65,5 +43,5 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel); - void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); - int ithc_dma_tx_init(struct ithc *ithc); - int ithc_dma_rx(struct ithc *ithc, u8 channel); --int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata); -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); - -diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c -new file mode 100644 -index 000000000000..065646ab499e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.c -@@ -0,0 +1,207 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+static int ithc_hid_start(struct hid_device *hdev) { return 0; } -+static void ithc_hid_stop(struct hid_device *hdev) { } -+static int ithc_hid_open(struct hid_device *hdev) { return 0; } -+static void ithc_hid_close(struct hid_device *hdev) { } -+ -+static int ithc_hid_parse(struct hid_device *hdev) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; -+ WRITE_ONCE(ithc->hid.parse_done, false); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); -+ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), -+ msecs_to_jiffies(200))) { -+ ithc_log_regs(ithc); -+ return 0; -+ } -+ if (retries > 5) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "failed to read report descriptor\n"); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -+ } -+} -+ -+static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -+ size_t len, unsigned char rtype, int reqtype) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ if (!buf || !len) -+ return -EINVAL; -+ -+ struct ithc_data d = { .size = len, .data = buf }; -+ buf[0] = reportnum; -+ -+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_OUTPUT_REPORT; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_SET_FEATURE; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -+ d.type = ITHC_DATA_GET_FEATURE; -+ d.data = &reportnum; -+ d.size = 1; -+ -+ // Prepare for response. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = buf; -+ ithc->hid.get_feature_size = len; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ -+ // Transmit 'get feature' request. -+ int r = CHECK(ithc_dma_tx, ithc, &d); -+ if (!r) { -+ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, -+ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); -+ if (!r) -+ r = -ETIMEDOUT; -+ else if (r < 0) -+ r = -EINTR; -+ else -+ r = 0; -+ } -+ -+ // If everything went ok, the buffer has been filled with the response data. -+ // Return the response size. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = NULL; -+ if (!r) -+ r = ithc->hid.get_feature_size; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ return r; -+ } -+ -+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -+ rtype, reqtype, reportnum); -+ return -EINVAL; -+} -+ -+// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to -+// cast away the const to avoid a compiler warning... -+#define NOCONST(x) ((void *)x) -+ -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) -+{ -+ WARN_ON(!ithc->hid.dev); -+ if (!ithc->hid.dev) -+ return; -+ -+ switch (d->type) { -+ -+ case ITHC_DATA_IGNORE: -+ return; -+ -+ case ITHC_DATA_ERROR: -+ CHECK(ithc_reset, ithc); -+ return; -+ -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ // Response to the report descriptor request sent by ithc_hid_parse(). -+ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); -+ WRITE_ONCE(ithc->hid.parse_done, true); -+ wake_up(&ithc->hid.wait_parse); -+ return; -+ -+ case ITHC_DATA_INPUT_REPORT: -+ { -+ // Standard HID input report. -+ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); -+ if (r < 0) { -+ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", -+ r, d->size, d->size ? *(u8 *)d->data : 0); -+ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, -+ d->data, min(d->size, 0x400u), 0); -+ } -+ return; -+ } -+ -+ case ITHC_DATA_GET_FEATURE: -+ { -+ // Response to a 'get feature' request sent by ithc_hid_raw_request(). -+ bool done = false; -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ if (ithc->hid.get_feature_buf) { -+ if (d->size < ithc->hid.get_feature_size) -+ ithc->hid.get_feature_size = d->size; -+ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); -+ ithc->hid.get_feature_buf = NULL; -+ done = true; -+ } -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ if (done) { -+ wake_up(&ithc->hid.wait_get_feature); -+ } else { -+ // Received data without a matching request, or the request already -+ // timed out. (XXX What's the correct thing to do here?) -+ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, -+ NOCONST(d->data), d->size, 1); -+ } -+ return; -+ } -+ -+ default: -+ pci_err(ithc->pci, "unhandled data type %i\n", d->type); -+ return; -+ } -+} -+ -+static struct hid_ll_driver ithc_ll_driver = { -+ .start = ithc_hid_start, -+ .stop = ithc_hid_stop, -+ .open = ithc_hid_open, -+ .close = ithc_hid_close, -+ .parse = ithc_hid_parse, -+ .raw_request = ithc_hid_raw_request, -+}; -+ -+static void ithc_hid_devres_release(struct device *dev, void *res) -+{ -+ struct hid_device **hidm = res; -+ if (*hidm) -+ hid_destroy_device(*hidm); -+} -+ -+int ithc_hid_init(struct ithc *ithc) -+{ -+ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -+ if (!hidm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, hidm); -+ struct hid_device *hid = hid_allocate_device(); -+ if (IS_ERR(hid)) -+ return PTR_ERR(hid); -+ *hidm = hid; -+ -+ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -+ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -+ hid->ll_driver = &ithc_ll_driver; -+ hid->bus = BUS_PCI; -+ hid->vendor = ithc->vendor_id; -+ hid->product = ithc->product_id; -+ hid->version = 0x100; -+ hid->dev.parent = &ithc->pci->dev; -+ hid->driver_data = ithc; -+ -+ ithc->hid.dev = hid; -+ -+ init_waitqueue_head(&ithc->hid.wait_parse); -+ init_waitqueue_head(&ithc->hid.wait_get_feature); -+ mutex_init(&ithc->hid.get_feature_mutex); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h -new file mode 100644 -index 000000000000..599eb912c8c8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+enum ithc_data_type { -+ ITHC_DATA_IGNORE, -+ ITHC_DATA_RAW, -+ ITHC_DATA_ERROR, -+ ITHC_DATA_REPORT_DESCRIPTOR, -+ ITHC_DATA_INPUT_REPORT, -+ ITHC_DATA_OUTPUT_REPORT, -+ ITHC_DATA_GET_FEATURE, -+ ITHC_DATA_SET_FEATURE, -+}; -+ -+struct ithc_data { -+ enum ithc_data_type type; -+ u32 size; -+ const void *data; -+}; -+ -+struct ithc_hid { -+ struct hid_device *dev; -+ bool parse_done; -+ wait_queue_head_t wait_parse; -+ wait_queue_head_t wait_get_feature; -+ struct mutex get_feature_mutex; -+ void *get_feature_buf; -+ size_t get_feature_size; -+}; -+ -+int ithc_hid_init(struct ithc *ithc); -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); -+ -diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c -new file mode 100644 -index 000000000000..5c1da11e3f1d ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.c -@@ -0,0 +1,252 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) -+#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) -+ -+#define DEVCFG_TOUCH_MASK 0x3f -+#define DEVCFG_TOUCH_ENABLE BIT(0) -+#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) -+#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) -+#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) -+#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) -+ -+#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" -+ -+#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) -+#define DEVCFG_SPI_CLKDIV_8 BIT(4) -+#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) -+#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) -+#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) -+#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) -+#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) -+#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat -+#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) -+#define DEVCFG_SPI_UNKNOWN_25 BIT(25) -+#define DEVCFG_SPI_UNKNOWN_26 BIT(26) -+#define DEVCFG_SPI_UNKNOWN_27 BIT(27) -+#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this -+#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? -+ -+struct ithc_device_config { // (Example values are from an SP7+.) -+ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) -+ u32 error; // 04 = 0x00000000 -+ u32 dma_buf_sizes; // 08 = 0x000a00ff -+ u32 touch_cfg; // 0c = 0x0000001c -+ u32 touch_state; // 10 = 0x0000001c -+ u32 device_id; // 14 = 0x43495424 = "$TIC" -+ u32 spi_config; // 18 = 0xfda00a2e -+ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. -+ u16 product_id; // 1e = 0x0c1a -+ u32 revision; // 20 = 0x00000001 -+ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) -+ u32 command; // 28 = 0x00000000 -+ u32 fw_mode; // 2c = 0x00000000 (for fw update?) -+ u32 _unknown_30; // 30 = 0x00000000 -+ u8 eds_minor_ver; // 34 = 0x5e -+ u8 eds_major_ver; // 35 = 0x03 -+ u8 interface_rev; // 36 = 0x04 -+ u8 eu_kernel_ver; // 37 = 0x04 -+ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) -+ u32 _unknown_3c; // 3c = 0x00000002 -+}; -+static_assert(sizeof(struct ithc_device_config) == 64); -+ -+#define RX_CODE_INPUT_REPORT 3 -+#define RX_CODE_FEATURE_REPORT 4 -+#define RX_CODE_REPORT_DESCRIPTOR 5 -+#define RX_CODE_RESET 7 -+ -+#define TX_CODE_SET_FEATURE 3 -+#define TX_CODE_GET_FEATURE 4 -+#define TX_CODE_OUTPUT_REPORT 5 -+#define TX_CODE_GET_REPORT_DESCRIPTOR 7 -+ -+static int ithc_set_device_enabled(struct ithc *ithc, bool enable) -+{ -+ u32 x = ithc->legacy_touch_cfg = -+ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | -+ DEVCFG_TOUCH_HID_REPORT_ENABLE | -+ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); -+ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -+ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); -+} -+ -+int ithc_legacy_init(struct ithc *ithc) -+{ -+ // Since we don't yet know which SPI config the device wants, use default speed and mode -+ // initially for reading config data. -+ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); -+ -+ // Setting the following bit seems to make reading the config more reliable. -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ // Setting this bit may be necessary on some ADL devices. -+ switch (ithc->pci->device) { -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); -+ break; -+ } -+ -+ // Take the touch device out of reset. -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -+ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) -+ break; -+ if (retries > 5) { -+ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", -+ readl(&ithc->regs->irq_cause)); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ if (msleep_interruptible(1000)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ -+ // Read configuration data. -+ u32 spi_cfg; -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ struct ithc_device_config config = { 0 }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); -+ u32 *p = (void *)&config; -+ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { -+ spi_cfg = config.spi_config; -+ ithc->vendor_id = config.vendor_id; -+ ithc->product_id = config.product_id; -+ ithc->product_rev = config.revision; -+ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); -+ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); -+ ithc->legacy_touch_cfg = config.touch_cfg; -+ ithc->have_config = true; -+ break; -+ } -+ if (retries > 10) { -+ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -+ config.device_id); -+ return -EIO; -+ } -+ pci_warn(ithc->pci, "failed to read config, retrying\n"); -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ // Apply SPI config and enable touch device. -+ CHECK_RET(ithc_set_spi_config, ithc, -+ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, -+ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : -+ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : -+ SPI_MODE_SINGLE, -+ SPI_MODE_SINGLE); -+ CHECK_RET(ithc_set_device_enabled, ithc, true); -+ ithc_log_regs(ithc); -+ return 0; -+} -+ -+void ithc_legacy_exit(struct ithc *ithc) -+{ -+ CHECK(ithc_set_device_enabled, ithc, false); -+} -+ -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct { -+ u32 code; -+ u32 data_size; -+ u32 _unknown[14]; -+ } *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // Note: RX data is not padded, even though TX data must be padded. -+ if (len != sizeof(*hdr) + hdr->data_size) -+ return -EMSGSIZE; -+ -+ dest->data = hdr + 1; -+ dest->size = hdr->data_size; -+ -+ switch (hdr->code) { -+ case RX_CODE_RESET: -+ // The THC sends a reset request when we need to reinitialize the device. -+ // This usually only happens if we send an invalid command or put the device -+ // in a bad state. -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case RX_CODE_REPORT_DESCRIPTOR: -+ // The descriptor is preceded by 8 nul bytes. -+ if (hdr->data_size < 8) -+ return -ENODATA; -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = (char *)(hdr + 1) + 8; -+ dest->size = hdr->data_size - 8; -+ return 0; -+ case RX_CODE_INPUT_REPORT: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ return 0; -+ case RX_CODE_FEATURE_REPORT: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct { -+ u32 code; -+ u32 data_size; -+ } *hdr = dest; -+ -+ size_t src_size = src->size; -+ const void *src_data = src->data; -+ const u64 get_report_desc_data = 0; -+ u32 code; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ code = TX_CODE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ code = TX_CODE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ code = TX_CODE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ code = TX_CODE_GET_REPORT_DESCRIPTOR; -+ src_size = sizeof(get_report_desc_data); -+ src_data = &get_report_desc_data; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->code = code; -+ hdr->data_size = src_size; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h -new file mode 100644 -index 000000000000..28d692462072 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.h -@@ -0,0 +1,8 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+int ithc_legacy_init(struct ithc *ithc); -+void ithc_legacy_exit(struct ithc *ithc); -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -index 87ed4aa70fda..2acf02e41d40 100644 ---- a/drivers/hid/ithc/ithc-main.c -+++ b/drivers/hid/ithc/ithc-main.c -@@ -5,28 +5,6 @@ - MODULE_DESCRIPTION("Intel Touch Host Controller driver"); - MODULE_LICENSE("Dual BSD/GPL"); - --// Lakefield --#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 --#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 --// Tiger Lake --#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 --#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 --#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 --#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 --// Alder Lake --#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 --#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 --#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 --#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 --#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 --#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 --// Raptor Lake --#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 --#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 --// Meteor Lake --#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 --#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a -- - static const struct pci_device_id ithc_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, -@@ -66,15 +44,13 @@ static bool ithc_use_rx1 = true; - module_param_named(rx1, ithc_use_rx1, bool, 0); - MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); - --// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering. --static int ithc_dma_latency_us = 200; --module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0); --MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS"); -+static int ithc_active_ltr_us = -1; -+module_param_named(activeltr, ithc_active_ltr_us, int, 0); -+MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); - --// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering. --static unsigned int ithc_dma_early_us = 2000; --module_param_named(dma_early_us, ithc_dma_early_us, uint, 0); --MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)"); -+static int ithc_idle_ltr_us = -1; -+module_param_named(idleltr, ithc_idle_ltr_us, int, 0); -+MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); - - static bool ithc_log_regs_enabled = false; - module_param_named(logregs, ithc_log_regs_enabled, bool, 0); -@@ -82,44 +58,30 @@ MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); - - // Sysfs attributes - --static bool ithc_is_config_valid(struct ithc *ithc) --{ -- return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC; --} -- - static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) - { - struct ithc *ithc = dev_get_drvdata(dev); -- if (!ithc || !ithc_is_config_valid(ithc)) -+ if (!ithc || !ithc->have_config) - return -ENODEV; -- return sprintf(buf, "0x%04x", ithc->config.vendor_id); -+ return sprintf(buf, "0x%04x", ithc->vendor_id); - } - static DEVICE_ATTR_RO(vendor); - static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf) - { - struct ithc *ithc = dev_get_drvdata(dev); -- if (!ithc || !ithc_is_config_valid(ithc)) -+ if (!ithc || !ithc->have_config) - return -ENODEV; -- return sprintf(buf, "0x%04x", ithc->config.product_id); -+ return sprintf(buf, "0x%04x", ithc->product_id); - } - static DEVICE_ATTR_RO(product); - static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) - { - struct ithc *ithc = dev_get_drvdata(dev); -- if (!ithc || !ithc_is_config_valid(ithc)) -+ if (!ithc || !ithc->have_config) - return -ENODEV; -- return sprintf(buf, "%u", ithc->config.revision); -+ return sprintf(buf, "%u", ithc->product_rev); - } - static DEVICE_ATTR_RO(revision); --static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) --{ -- struct ithc *ithc = dev_get_drvdata(dev); -- if (!ithc || !ithc_is_config_valid(ithc)) -- return -ENODEV; -- u32 v = ithc->config.fw_version; -- return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff); --} --static DEVICE_ATTR_RO(fw_version); - - static const struct attribute_group *ithc_attribute_groups[] = { - &(const struct attribute_group){ -@@ -128,185 +90,26 @@ static const struct attribute_group *ithc_attribute_groups[] = { - &dev_attr_vendor.attr, - &dev_attr_product.attr, - &dev_attr_revision.attr, -- &dev_attr_fw_version.attr, - NULL - }, - }, - NULL - }; - --// HID setup -- --static int ithc_hid_start(struct hid_device *hdev) { return 0; } --static void ithc_hid_stop(struct hid_device *hdev) { } --static int ithc_hid_open(struct hid_device *hdev) { return 0; } --static void ithc_hid_close(struct hid_device *hdev) { } -- --static int ithc_hid_parse(struct hid_device *hdev) --{ -- struct ithc *ithc = hdev->driver_data; -- u64 val = 0; -- WRITE_ONCE(ithc->hid_parse_done, false); -- for (int retries = 0; ; retries++) { -- CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val); -- if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done), -- msecs_to_jiffies(200))) -- return 0; -- if (retries > 5) { -- pci_err(ithc->pci, "failed to read report descriptor\n"); -- return -ETIMEDOUT; -- } -- pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -- } --} -- --static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -- size_t len, unsigned char rtype, int reqtype) --{ -- struct ithc *ithc = hdev->driver_data; -- if (!buf || !len) -- return -EINVAL; -- u32 code; -- if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -- code = DMA_TX_CODE_OUTPUT_REPORT; -- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -- code = DMA_TX_CODE_SET_FEATURE; -- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -- code = DMA_TX_CODE_GET_FEATURE; -- } else { -- pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -- rtype, reqtype, reportnum); -- return -EINVAL; -- } -- buf[0] = reportnum; -- -- if (reqtype == HID_REQ_GET_REPORT) { -- // Prepare for response. -- mutex_lock(&ithc->hid_get_feature_mutex); -- ithc->hid_get_feature_buf = buf; -- ithc->hid_get_feature_size = len; -- mutex_unlock(&ithc->hid_get_feature_mutex); -- -- // Transmit 'get feature' request. -- int r = CHECK(ithc_dma_tx, ithc, code, 1, buf); -- if (!r) { -- r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature, -- !ithc->hid_get_feature_buf, msecs_to_jiffies(1000)); -- if (!r) -- r = -ETIMEDOUT; -- else if (r < 0) -- r = -EINTR; -- else -- r = 0; -- } -- -- // If everything went ok, the buffer has been filled with the response data. -- // Return the response size. -- mutex_lock(&ithc->hid_get_feature_mutex); -- ithc->hid_get_feature_buf = NULL; -- if (!r) -- r = ithc->hid_get_feature_size; -- mutex_unlock(&ithc->hid_get_feature_mutex); -- return r; -- } -- -- // 'Set feature', or 'output report'. These don't have a response. -- CHECK_RET(ithc_dma_tx, ithc, code, len, buf); -- return 0; --} -- --static struct hid_ll_driver ithc_ll_driver = { -- .start = ithc_hid_start, -- .stop = ithc_hid_stop, -- .open = ithc_hid_open, -- .close = ithc_hid_close, -- .parse = ithc_hid_parse, -- .raw_request = ithc_hid_raw_request, --}; -- --static void ithc_hid_devres_release(struct device *dev, void *res) --{ -- struct hid_device **hidm = res; -- if (*hidm) -- hid_destroy_device(*hidm); --} -- --static int ithc_hid_init(struct ithc *ithc) --{ -- struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -- if (!hidm) -- return -ENOMEM; -- devres_add(&ithc->pci->dev, hidm); -- struct hid_device *hid = hid_allocate_device(); -- if (IS_ERR(hid)) -- return PTR_ERR(hid); -- *hidm = hid; -- -- strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -- strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -- hid->ll_driver = &ithc_ll_driver; -- hid->bus = BUS_PCI; -- hid->vendor = ithc->config.vendor_id; -- hid->product = ithc->config.product_id; -- hid->version = 0x100; -- hid->dev.parent = &ithc->pci->dev; -- hid->driver_data = ithc; -- -- ithc->hid = hid; -- return 0; --} -- - // Interrupts/polling - --static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t) --{ -- struct ithc *ithc = container_of(t, struct ithc, activity_start_timer); -- ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC); -- return HRTIMER_NORESTART; --} -- --static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t) --{ -- struct ithc *ithc = container_of(t, struct ithc, activity_end_timer); -- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -- return HRTIMER_NORESTART; --} -- --void ithc_set_active(struct ithc *ithc, unsigned int duration_us) --{ -- if (ithc_dma_latency_us < 0) -- return; -- // When CPU usage is very low, the CPU can enter various low power states (C2-C10). -- // This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be -- // set when this happens. The amount of truncated messages can become very high, resulting -- // in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency -- // QoS request to prevent the CPU from entering low power states during touch interactions. -- cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us); -- hrtimer_start_range_ns(&ithc->activity_end_timer, -- ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL); --} -- --static int ithc_set_device_enabled(struct ithc *ithc, bool enable) --{ -- u32 x = ithc->config.touch_cfg = -- (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 | -- (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0); -- return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -- offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); --} -- - static void ithc_disable_interrupts(struct ithc *ithc) - { - writel(0, &ithc->regs->error_control); - bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); -- bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); -- bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); - bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); - } - - static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) - { -- writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA, -+ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, - &ithc->regs->dma_rx[channel].status); - } - -@@ -325,39 +128,22 @@ static void ithc_process(struct ithc *ithc) - { - ithc_log_regs(ithc); - -+ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. -+ // It does not appear to automatically go back to idle, so we switch it back here, since -+ // the DMA transfer should be complete. -+ ithc_set_ltr_idle(ithc); -+ - bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; - bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; - -- // Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer -- ktime_t t = ktime_get(); -- ktime_t dt = ktime_sub(t, ithc->last_rx_time); -- if (rx0 || rx1) { -- ithc->last_rx_time = t; -- if (dt > ms_to_ktime(100)) { -- ithc->cur_rx_seq_count = 0; -- ithc->cur_rx_seq_errors = 0; -- } -- ithc->cur_rx_seq_count++; -- if (!ithc_use_polling && ithc_dma_latency_us >= 0) { -- // Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below) -- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -- hrtimer_try_to_cancel(&ithc->activity_end_timer); -- } -- } -- - // Read and clear error bits - u32 err = readl(&ithc->regs->error_flags); - if (err) { - writel(err, &ithc->regs->error_flags); - if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) - pci_err(ithc->pci, "error flags: 0x%08x\n", err); -- if (err & ERROR_FLAG_DMA_RX_TIMEOUT) { -- // Only log an error if we see a significant number of these errors. -- ithc->cur_rx_seq_errors++; -- if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10) -- pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n", -- ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt)); -- } -+ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); - } - - // Process DMA rx -@@ -372,12 +158,6 @@ static void ithc_process(struct ithc *ithc) - ithc_dma_rx(ithc, 1); - } - -- // Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT -- if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) { -- ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us)); -- hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS); -- } -- - ithc_log_regs(ithc); - } - -@@ -403,12 +183,8 @@ static int ithc_poll_thread(void *arg) - ithc_process(ithc); - // Decrease polling interval to 20ms if we received data, otherwise slowly - // increase it up to 200ms. -- if (n != ithc->dma_rx[1].num_received) { -- ithc_set_active(ithc, 100 * USEC_PER_MSEC); -- sleep = 20; -- } else { -- sleep = min(200u, sleep + (sleep >> 4) + 1); -- } -+ sleep = n != ithc->dma_rx[1].num_received ? 20 -+ : min(200u, sleep + (sleep >> 4) + 1); - msleep_interruptible(sleep); - } - return 0; -@@ -431,73 +207,44 @@ static void ithc_disable(struct ithc *ithc) - - static int ithc_init_device(struct ithc *ithc) - { -+ // Read ACPI config for QuickSPI mode -+ struct ithc_acpi_config cfg = { 0 }; -+ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); -+ if (!cfg.has_config) -+ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); -+ else -+ ithc_print_acpi_config(ithc, &cfg); -+ ithc->use_quickspi = cfg.has_config; -+ -+ // Shut down device - ithc_log_regs(ithc); - bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; - ithc_disable(ithc); - CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); -- -- // Since we don't yet know which SPI config the device wants, use default speed and mode -- // initially for reading config data. -- ithc_set_spi_config(ithc, 10, 0); -- -- // Setting the following bit seems to make reading the config more reliable. -- bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000); -+ ithc_log_regs(ithc); - - // If the device was previously enabled, wait a bit to make sure it's fully shut down. - if (was_enabled) - if (msleep_interruptible(100)) - return -EINTR; - -- // Take the touch device out of reset. -- bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -- CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -- for (int retries = 0; ; retries++) { -- ithc_log_regs(ithc); -- bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -- if (!waitl(ithc, &ithc->regs->state, 0xf, 2)) -- break; -- if (retries > 5) { -- pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state)); -- return -ETIMEDOUT; -- } -- pci_warn(ithc->pci, "invalid state, retrying reset\n"); -- bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -- if (msleep_interruptible(1000)) -- return -EINTR; -- } -- ithc_log_regs(ithc); -+ // Set Latency Tolerance Reporting config. The device will automatically -+ // apply these values depending on whether it is active or idle. -+ // If active value is too high, DMA buffer data can become truncated. -+ // By default, we set the active LTR value to 100us, and idle to 100ms. -+ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 -+ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 -+ : 100 * 1000; -+ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 -+ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 -+ : 100 * 1000 * 1000; -+ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); -+ -+ if (ithc->use_quickspi) -+ CHECK_RET(ithc_quickspi_init, ithc, &cfg); -+ else -+ CHECK_RET(ithc_legacy_init, ithc); - -- // Waiting for the following status bit makes reading config much more reliable, -- // however the official driver does not seem to do this... -- CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4); -- -- // Read configuration data. -- for (int retries = 0; ; retries++) { -- ithc_log_regs(ithc); -- memset(&ithc->config, 0, sizeof(ithc->config)); -- CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config); -- u32 *p = (void *)&ithc->config; -- pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -- if (ithc_is_config_valid(ithc)) -- break; -- if (retries > 10) { -- pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -- ithc->config.device_id); -- return -EIO; -- } -- pci_warn(ithc->pci, "failed to read config, retrying\n"); -- if (msleep_interruptible(100)) -- return -EINTR; -- } -- ithc_log_regs(ithc); -- -- // Apply SPI config and enable touch device. -- CHECK_RET(ithc_set_spi_config, ithc, -- DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config), -- DEVCFG_SPI_MODE(ithc->config.spi_config)); -- CHECK_RET(ithc_set_device_enabled, ithc, true); -- ithc_log_regs(ithc); - return 0; - } - -@@ -527,11 +274,11 @@ static void ithc_stop(void *res) - CHECK(kthread_stop, ithc->poll_thread); - if (ithc->irq >= 0) - disable_irq(ithc->irq); -- CHECK(ithc_set_device_enabled, ithc, false); -+ if (ithc->use_quickspi) -+ ithc_quickspi_exit(ithc); -+ else -+ ithc_legacy_exit(ithc); - ithc_disable(ithc); -- hrtimer_cancel(&ithc->activity_start_timer); -- hrtimer_cancel(&ithc->activity_end_timer); -- cpu_latency_qos_remove_request(&ithc->activity_qos); - - // Clear DMA config. - for (unsigned int i = 0; i < 2; i++) { -@@ -570,9 +317,6 @@ static int ithc_start(struct pci_dev *pci) - ithc->irq = -1; - ithc->pci = pci; - snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); -- init_waitqueue_head(&ithc->wait_hid_parse); -- init_waitqueue_head(&ithc->wait_hid_get_feature); -- mutex_init(&ithc->hid_get_feature_mutex); - pci_set_drvdata(pci, ithc); - CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); - if (ithc_log_regs_enabled) -@@ -596,6 +340,9 @@ static int ithc_start(struct pci_dev *pci) - - // Initialize THC and touch device. - CHECK_RET(ithc_init_device, ithc); -+ -+ // Initialize HID and DMA. -+ CHECK_RET(ithc_hid_init, ithc); - CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups); - if (ithc_use_rx0) - CHECK_RET(ithc_dma_rx_init, ithc, 0); -@@ -603,18 +350,10 @@ static int ithc_start(struct pci_dev *pci) - CHECK_RET(ithc_dma_rx_init, ithc, 1); - CHECK_RET(ithc_dma_tx_init, ithc); - -- cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -- hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); -- ithc->activity_start_timer.function = ithc_activity_start_timer_callback; -- hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -- ithc->activity_end_timer.function = ithc_activity_end_timer_callback; -- - // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are - // disabled BEFORE the buffers are freed. - CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); - -- CHECK_RET(ithc_hid_init, ithc); -- - // Start polling/IRQ. - if (ithc_use_polling) { - pci_info(pci, "using polling instead of irq\n"); -@@ -637,9 +376,11 @@ static int ithc_start(struct pci_dev *pci) - - // hid_add_device() can only be called after irq/polling is started and DMA is enabled, - // because it calls ithc_hid_parse() which reads the report descriptor via DMA. -- CHECK_RET(hid_add_device, ithc->hid); -+ CHECK_RET(hid_add_device, ithc->hid.dev); -+ -+ CHECK(ithc_debug_init_device, ithc); - -- CHECK(ithc_debug_init, ithc); -+ ithc_set_ltr_idle(ithc); - - pci_dbg(pci, "started\n"); - return 0; -@@ -710,17 +451,20 @@ static struct pci_driver ithc_driver = { - .thaw = ithc_thaw, - .restore = ithc_restore, - }, -+ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, - //.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway - }; - - static int __init ithc_init(void) - { -+ ithc_debug_init_module(); - return pci_register_driver(&ithc_driver); - } - - static void __exit ithc_exit(void) - { - pci_unregister_driver(&ithc_driver); -+ ithc_debug_exit_module(); - } - - module_init(ithc_init); -diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c -new file mode 100644 -index 000000000000..760e55ead078 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.c -@@ -0,0 +1,578 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+// Some public THC/QuickSPI documentation can be found in: -+// - Intel Firmware Support Package repo: https://github.com/intel/FSP -+// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 -+ -+#include "ithc.h" -+ -+static const guid_t guid_hidspi = -+ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); -+static const guid_t guid_thc_quickspi = -+ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); -+static const guid_t guid_thc_ltr = -+ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); -+ -+// TODO The HIDSPI spec says revision should be 3. Should we try both? -+#define DSM_REV 2 -+ -+struct hidspi_header { -+ u8 type; -+ u16 len; -+ u8 id; -+} __packed; -+static_assert(sizeof(struct hidspi_header) == 4); -+ -+#define HIDSPI_INPUT_TYPE_DATA 1 -+#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 -+#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 -+#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 -+#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 -+#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 -+#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 -+#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 -+#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 -+ -+#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 -+#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 -+#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 -+#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 -+#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 -+#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 -+#define HIDSPI_OUTPUT_TYPE_COMMAND 7 -+ -+struct hidspi_device_descriptor { -+ u16 wDeviceDescLength; -+ u16 bcdVersion; -+ u16 wReportDescLength; -+ u16 wMaxInputLength; -+ u16 wMaxOutputLength; -+ u16 wMaxFragmentLength; -+ u16 wVendorID; -+ u16 wProductID; -+ u16 wVersionID; -+ u16 wFlags; -+ u32 dwReserved; -+}; -+static_assert(sizeof(struct hidspi_device_descriptor) == 24); -+ -+static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_INTEGER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); -+ *dest = (u32)o->integer.value; -+ ACPI_FREE(o); -+ return 1; -+} -+ -+static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_BUFFER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ if (o->buffer.length != len) { -+ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", -+ guid, func, o->buffer.length, len); -+ ACPI_FREE(o); -+ return -1; -+ } -+ memcpy(dest, o->buffer.pointer, len); -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); -+ ACPI_FREE(o); -+ return 1; -+} -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) -+{ -+ int r; -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ -+ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); -+ if (!cfg->has_config) -+ return 0; -+ -+ // HIDSPI settings -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_header_address = r > 0; -+ if (r > 0 && cfg->input_report_header_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", -+ cfg->input_report_header_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_body_address = r > 0; -+ if (r > 0 && cfg->input_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", -+ cfg->input_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_output_report_body_address = r > 0; -+ if (r > 0 && cfg->output_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", -+ cfg->output_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_read_opcode = r > 0; -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_write_opcode = r > 0; -+ -+ u32 flags; -+ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); -+ if (r < 0) -+ return r; -+ cfg->has_read_mode = cfg->has_write_mode = r > 0; -+ if (r > 0) { -+ cfg->read_mode = (flags >> 14) & 3; -+ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; -+ } -+ -+ // Quick SPI settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); -+ if (r < 0) -+ return r; -+ cfg->has_spi_frequency = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); -+ if (r < 0) -+ return r; -+ cfg->has_limit_packet_size = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); -+ if (r < 0) -+ return r; -+ cfg->has_tx_delay = r > 0; -+ if (r > 0) -+ cfg->tx_delay &= 0xffff; -+ -+ // LTR settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_active_ltr = r > 0; -+ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { -+ if (cfg->active_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", -+ cfg->active_ltr); -+ cfg->active_ltr = 500; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_idle_ltr = r > 0; -+ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { -+ if (cfg->idle_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", -+ cfg->idle_ltr); -+ cfg->idle_ltr = 500; -+ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) -+ cfg->idle_ltr = cfg->active_ltr; -+ } -+ -+ return 0; -+} -+ -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ if (!cfg->has_config) { -+ pci_info(ithc->pci, "No ACPI config"); -+ return; -+ } -+ -+ char input_report_header_address[16] = "-"; -+ if (cfg->has_input_report_header_address) -+ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); -+ char input_report_body_address[16] = "-"; -+ if (cfg->has_input_report_body_address) -+ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); -+ char output_report_body_address[16] = "-"; -+ if (cfg->has_output_report_body_address) -+ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); -+ char read_opcode[16] = "-"; -+ if (cfg->has_read_opcode) -+ sprintf(read_opcode, "0x%02x", cfg->read_opcode); -+ char write_opcode[16] = "-"; -+ if (cfg->has_write_opcode) -+ sprintf(write_opcode, "0x%02x", cfg->write_opcode); -+ char read_mode[16] = "-"; -+ if (cfg->has_read_mode) -+ sprintf(read_mode, "%i", cfg->read_mode); -+ char write_mode[16] = "-"; -+ if (cfg->has_write_mode) -+ sprintf(write_mode, "%i", cfg->write_mode); -+ char spi_frequency[16] = "-"; -+ if (cfg->has_spi_frequency) -+ sprintf(spi_frequency, "%u", cfg->spi_frequency); -+ char limit_packet_size[16] = "-"; -+ if (cfg->has_limit_packet_size) -+ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); -+ char tx_delay[16] = "-"; -+ if (cfg->has_tx_delay) -+ sprintf(tx_delay, "%u", cfg->tx_delay); -+ char active_ltr[16] = "-"; -+ if (cfg->has_active_ltr) -+ sprintf(active_ltr, "%u", cfg->active_ltr); -+ char idle_ltr[16] = "-"; -+ if (cfg->has_idle_ltr) -+ sprintf(idle_ltr, "%u", cfg->idle_ltr); -+ -+ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", -+ input_report_header_address, input_report_body_address, output_report_body_address, -+ read_opcode, write_opcode, read_mode, write_mode, -+ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); -+} -+ -+static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); -+ -+ // SPI frequency and mode -+ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { -+ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); -+ return -EINVAL; -+ } -+ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); -+ bool clkdiv8 = clkdiv > 7; -+ if (clkdiv8) -+ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); -+ if (!clkdiv) -+ clkdiv = 1; -+ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, -+ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, -+ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); -+ -+ // SPI addresses and opcodes -+ if (cfg->has_input_report_header_address) -+ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); -+ if (cfg->has_input_report_body_address) -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); -+ if (cfg->has_output_report_body_address) -+ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); -+ -+ if (cfg->has_read_opcode) { -+ writeb(cfg->read_opcode, &ithc->regs->read_opcode); -+ writeb(cfg->read_opcode, &ithc->regs->read_opcode_single); -+ writeb(cfg->read_opcode, &ithc->regs->read_opcode_dual); -+ writeb(cfg->read_opcode, &ithc->regs->read_opcode_quad); -+ } -+ if (cfg->has_write_opcode) { -+ writeb(cfg->write_opcode, &ithc->regs->write_opcode); -+ writeb(cfg->write_opcode, &ithc->regs->write_opcode_single); -+ writeb(cfg->write_opcode, &ithc->regs->write_opcode_dual); -+ writeb(cfg->write_opcode, &ithc->regs->write_opcode_quad); -+ } -+ ithc_log_regs(ithc); -+ -+ // The rest... -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), -+ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); -+ -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), -+ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(2)); -+ -+ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), -+ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); -+ -+ bitsl_set(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); -+ -+ return 0; -+} -+ -+static int wait_for_report(struct ithc *ithc) -+{ -+ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, -+ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); -+ -+ u32 h = readl(&ithc->regs->input_header); -+ ithc_log_regs(ithc); -+ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE -+ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { -+ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); -+ return -ENODATA; -+ } -+ return INPUT_HEADER_REPORT_LENGTH(h) * 4; -+} -+ -+static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing HIDSPI\n"); -+ -+ // HIDSPI initialization sequence: -+ // "1. The host shall invoke the ACPI reset method to clear the device state." -+ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); -+ if (ACPI_FAILURE(s)) { -+ pci_err(ithc->pci, "ACPI reset failed\n"); -+ return -EIO; -+ } -+ -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ -+ // "2. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing a device reset response." -+ int size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(struct hidspi_header)) { -+ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "3. The host shall read the reset response from the device at the Input Report addresses -+ // specified in ACPI." -+ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; -+ struct { -+ struct hidspi_header header; -+ union { -+ struct hidspi_device_descriptor device_desc; -+ u32 data[16]; -+ }; -+ } resp = { 0 }; -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { -+ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); -+ return -ENOMSG; -+ } -+ -+ // "4. The host shall then write an Output Report to the device at the Output Report Address -+ // specified in ACPI, requesting the Device Descriptor from the device." -+ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; -+ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); -+ -+ // "5. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing the Device Descriptor." -+ size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { -+ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "6. The host shall read the Device Descriptor from the Input Report addresses specified -+ // in ACPI." -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ memset(&resp, 0, sizeof(resp)); -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { -+ pci_err(ithc->pci, "received type %i instead of device descriptor\n", -+ resp.header.type); -+ return -ENOMSG; -+ } -+ struct hidspi_device_descriptor *d = &resp.device_desc; -+ if (resp.header.len < sizeof(*d)) { -+ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", -+ resp.header.len); -+ return -EMSGSIZE; -+ } -+ if (d->wDeviceDescLength != sizeof(*d)) { -+ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", -+ d->wDeviceDescLength); -+ return -EMSGSIZE; -+ } -+ -+ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", -+ d->bcdVersion, d->wReportDescLength, -+ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, -+ d->wVendorID, d->wProductID, d->wVersionID, -+ d->wFlags, d->dwReserved); -+ -+ ithc->vendor_id = d->wVendorID; -+ ithc->product_id = d->wProductID; -+ ithc->product_rev = d->wVersionID; -+ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, -+ d->wReportDescLength + sizeof(struct hidspi_header)); -+ ithc->max_tx_size = d->wMaxOutputLength; -+ ithc->have_config = true; -+ -+ // "7. The device and host shall then enter their "Ready" states - where the device may -+ // begin sending Input Reports, and the device shall be prepared for Output Reports from -+ // the host." -+ -+ return 0; -+} -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); -+ ithc_log_regs(ithc); -+ -+ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, -+ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); -+ -+ // TODO Do we need to set any of the following bits here? -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); -+ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ ithc_log_regs(ithc); -+ -+ return 0; -+} -+ -+void ithc_quickspi_exit(struct ithc *ithc) -+{ -+ // TODO Should we send HIDSPI 'power off' command? -+ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; -+ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; -+ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() -+} -+ -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct hidspi_header *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // TODO Do we need to handle HIDSPI packet fragmentation? -+ if (len < sizeof(*hdr) + hdr->len) -+ return -EMSGSIZE; -+ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) -+ return -EMSGSIZE; -+ -+ switch (hdr->type) { -+ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: -+ // TODO "When the device detects an error condition, it may interrupt and make -+ // available to the host an Input Report containing an unsolicited Reset Response. -+ // After receiving an unsolicited Reset Response, the host shall initiate the -+ // request procedure from step (4) in the [HIDSPI initialization] process." -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = hdr + 1; -+ dest->size = hdr->len; -+ return 0; -+ case HIDSPI_INPUT_TYPE_DATA: -+ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: -+ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_IGNORE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct hidspi_header *hdr = dest; -+ -+ size_t src_size = src->size; -+ const u8 *src_data = src->data; -+ u8 type; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; -+ src_size = 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ u8 id = 0; -+ if (src_size) { -+ id = *src_data++; -+ src_size--; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->type = type; -+ hdr->len = (u16)src_size; -+ hdr->id = id; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h -new file mode 100644 -index 000000000000..74d882f6b2f0 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.h -@@ -0,0 +1,39 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+struct ithc_acpi_config { -+ bool has_config: 1; -+ bool has_input_report_header_address: 1; -+ bool has_input_report_body_address: 1; -+ bool has_output_report_body_address: 1; -+ bool has_read_opcode: 1; -+ bool has_write_opcode: 1; -+ bool has_read_mode: 1; -+ bool has_write_mode: 1; -+ bool has_spi_frequency: 1; -+ bool has_limit_packet_size: 1; -+ bool has_tx_delay: 1; -+ bool has_active_ltr: 1; -+ bool has_idle_ltr: 1; -+ u32 input_report_header_address; -+ u32 input_report_body_address; -+ u32 output_report_body_address; -+ u8 read_opcode; -+ u8 write_opcode; -+ u8 read_mode; -+ u8 write_mode; -+ u32 spi_frequency; -+ u32 limit_packet_size; -+ u32 tx_delay; // us/10 // TODO use? -+ u32 active_ltr; // ns/1024 -+ u32 idle_ltr; // ns/1024 -+}; -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+void ithc_quickspi_exit(struct ithc *ithc); -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c -index e058721886e3..c0f13506af20 100644 ---- a/drivers/hid/ithc/ithc-regs.c -+++ b/drivers/hid/ithc/ithc-regs.c -@@ -22,46 +22,104 @@ void bitsb(__iomem u8 *reg, u8 mask, u8 val) - - int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) - { -+ ithc_log_regs(ithc); - pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", - reg_num(reg), mask, val); - u32 x; - if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); - pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", - reg_num(reg), mask, val); - return -ETIMEDOUT; - } -+ ithc_log_regs(ithc); - pci_dbg(ithc->pci, "done waiting\n"); - return 0; - } - - int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) - { -+ ithc_log_regs(ithc); - pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", - reg_num(reg), mask, val); - u8 x; - if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); - pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", - reg_num(reg), mask, val); - return -ETIMEDOUT; - } -+ ithc_log_regs(ithc); - pci_dbg(ithc->pci, "done waiting\n"); - return 0; - } - --int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode) -+static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) - { -- pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode); -- if (mode == 3) -- mode = 2; -+ unsigned int s = 0; -+ u64 v = *ns; -+ while (v > 0x3ff) { -+ s++; -+ v >>= 5; -+ } -+ if (s > 5) { -+ s = 5; -+ v = 0x3ff; -+ } -+ *val = v; -+ *scale = s; -+ *ns = v << (5 * s); -+} -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) -+{ -+ unsigned int active_val, active_scale, idle_val, idle_scale; -+ calc_ltr(&active_ltr_ns, &active_val, &active_scale); -+ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); -+ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", -+ active_ltr_ns, idle_ltr_ns); -+ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | -+ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | -+ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), -+ &ithc->regs->ltr_config); -+} -+ -+void ithc_set_ltr_idle(struct ithc *ithc) -+{ -+ u32 ltr = readl(&ithc->regs->ltr_config); -+ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { -+ case LTR_CONFIG_STATUS_IDLE: -+ break; -+ case LTR_CONFIG_STATUS_ACTIVE: -+ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); -+ break; -+ default: -+ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); -+ break; -+ } -+} -+ -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) -+{ -+ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) -+ return -EINVAL; -+ static const char * const modes[] = { "single", "dual", "quad" }; -+ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", -+ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), -+ modes[read_mode], modes[write_mode]); - bitsl(&ithc->regs->spi_config, -- SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff), -- SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed)); -+ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | -+ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | -+ SPI_CONFIG_CLKDIV_8, -+ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | -+ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | -+ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); - return 0; - } - - int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) - { -- pci_dbg(ithc->pci, "SPI command %u, size %u, offset %u\n", command, size, offset); -+ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); - if (size > sizeof(ithc->regs->spi_cmd.data)) - return -EINVAL; - -diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h -index d4007d9e2bac..a9d236454644 100644 ---- a/drivers/hid/ithc/ithc-regs.h -+++ b/drivers/hid/ithc/ithc-regs.h -@@ -1,14 +1,34 @@ - /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ - -+#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) -+#define LTR_CONFIG_TOGGLE BIT(1) -+#define LTR_CONFIG_ENABLE_IDLE BIT(2) -+#define LTR_CONFIG_APPLY BIT(3) -+#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) -+#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) -+#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) -+#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) -+#define LTR_CONFIG_STATUS_ACTIVE BIT(30) -+#define LTR_CONFIG_STATUS_IDLE BIT(31) -+ - #define CONTROL_QUIESCE BIT(1) - #define CONTROL_IS_QUIESCED BIT(2) - #define CONTROL_NRESET BIT(3) -+#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) - #define CONTROL_READY BIT(29) - --#define SPI_CONFIG_MODE(x) (((x) & 3) << 2) --#define SPI_CONFIG_SPEED(x) (((x) & 7) << 4) --#define SPI_CONFIG_UNKNOWN_18(x) (((x) & 3) << 18) --#define SPI_CONFIG_SPEED2(x) (((x) & 0xf) << 20) // high bit = high speed mode? -+#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) -+#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) -+#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) -+#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) -+#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) -+#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write -+#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) -+ -+#define SPI_CLK_FREQ_BASE 125000000 -+#define SPI_MODE_SINGLE 0 -+#define SPI_MODE_DUAL 1 -+#define SPI_MODE_QUAD 2 - - #define ERROR_CONTROL_UNKNOWN_0 BIT(0) - #define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs -@@ -53,33 +73,71 @@ - #define DMA_TX_STATUS_UNKNOWN_2 BIT(2) - #define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? - -+#define INPUT_HEADER_VERSION(x) ((x) & 0xf) -+#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) -+#define INPUT_HEADER_SYNC(x) ((x) >> 24) -+#define INPUT_HEADER_VERSION_VALUE 3 -+#define INPUT_HEADER_SYNC_VALUE 0x5a -+ -+#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) -+#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) -+ -+#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) -+#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) -+#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) -+#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) -+#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) -+#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) -+#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) -+ - #define DMA_RX_CONTROL_ENABLE BIT(0) - #define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? - #define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? --#define DMA_RX_CONTROL_IRQ_UNKNOWN_4 BIT(4) // rx0 only? -+#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only - #define DMA_RX_CONTROL_IRQ_DATA BIT(5) - -+#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? - #define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? - #define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices - - #define DMA_RX_WRAP_FLAG BIT(7) - - #define DMA_RX_STATUS_ERROR BIT(3) --#define DMA_RX_STATUS_UNKNOWN_4 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) -+#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) - #define DMA_RX_STATUS_HAVE_DATA BIT(5) - #define DMA_RX_STATUS_ENABLED BIT(8) - -+#define INIT_UNKNOWN_GUC_2 BIT(2) -+#define INIT_UNKNOWN_3 BIT(3) -+#define INIT_UNKNOWN_GUC_4 BIT(4) -+#define INIT_UNKNOWN_5 BIT(5) -+#define INIT_UNKNOWN_31 BIT(31) -+ - // COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. - #define COUNTER_RESET BIT(31) - - struct ithc_registers { -- /* 0000 */ u32 _unknown_0000[1024]; -+ /* 0000 */ u32 _unknown_0000[5]; -+ /* 0014 */ u32 ltr_config; -+ /* 0018 */ u32 _unknown_0018[1018]; - /* 1000 */ u32 _unknown_1000; - /* 1004 */ u32 _unknown_1004; - /* 1008 */ u32 control_bits; - /* 100c */ u32 _unknown_100c; - /* 1010 */ u32 spi_config; -- /* 1014 */ u32 _unknown_1014[3]; -+ /* 1014 */ u8 read_opcode; // maybe for header? -+ /* 1015 */ u8 read_opcode_quad; -+ /* 1016 */ u8 read_opcode_dual; -+ /* 1017 */ u8 read_opcode_single; -+ /* 1018 */ u8 write_opcode; // not used? -+ /* 1019 */ u8 write_opcode_quad; -+ /* 101a */ u8 write_opcode_dual; -+ /* 101b */ u8 write_opcode_single; -+ /* 101c */ u32 _unknown_101c; - /* 1020 */ u32 error_control; - /* 1024 */ u32 error_status; // write to clear - /* 1028 */ u32 error_flags; // write to clear -@@ -100,12 +158,19 @@ struct ithc_registers { - /* 109a */ u8 _unknown_109a; - /* 109b */ u8 num_prds; - /* 109c */ u32 status; // write to clear -+ /* 10a0 */ u32 _unknown_10a0[5]; -+ /* 10b4 */ u32 spi_addr; - } dma_tx; -- /* 10a0 */ u32 _unknown_10a0[7]; -- /* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET -+ /* 10b8 */ u32 spi_header_addr; -+ union { -+ /* 10bc */ u32 irq_cause; // in legacy THC mode -+ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) -+ }; - /* 10c0 */ u32 _unknown_10c0[8]; - /* 10e0 */ u32 _unknown_10e0_counters[3]; -- /* 10ec */ u32 _unknown_10ec[5]; -+ /* 10ec */ u32 quickspi_config1; -+ /* 10f0 */ u32 quickspi_config2; -+ /* 10f4 */ u32 _unknown_10f4[3]; - struct { - /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() - /* 1108/1208 */ u8 num_bufs; -@@ -120,70 +185,30 @@ struct ithc_registers { - /* 1118/1218 */ u64 _unknown_1118_guc_addr; - /* 1120/1220 */ u32 _unknown_1120_guc; - /* 1124/1224 */ u32 _unknown_1124_guc; -- /* 1128/1228 */ u32 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related -+ /* 1128/1228 */ u32 init_unknown; - /* 112c/122c */ u32 _unknown_112c; - /* 1130/1230 */ u64 _unknown_1130_guc_addr; - /* 1138/1238 */ u32 _unknown_1138_guc; - /* 113c/123c */ u32 _unknown_113c; - /* 1140/1240 */ u32 _unknown_1140_guc; -- /* 1144/1244 */ u32 _unknown_1144[23]; -+ /* 1144/1244 */ u32 _unknown_1144[11]; -+ /* 1170/1270 */ u32 spi_addr; -+ /* 1174/1274 */ u32 _unknown_1174[11]; - /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; - /* 11b8/12b8 */ u32 _unknown_11b8[18]; - } dma_rx[2]; - }; - static_assert(sizeof(struct ithc_registers) == 0x1300); - --#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) --#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) -- --#define DEVCFG_TOUCH_MASK 0x3f --#define DEVCFG_TOUCH_ENABLE BIT(0) --#define DEVCFG_TOUCH_UNKNOWN_1 BIT(1) --#define DEVCFG_TOUCH_UNKNOWN_2 BIT(2) --#define DEVCFG_TOUCH_UNKNOWN_3 BIT(3) --#define DEVCFG_TOUCH_UNKNOWN_4 BIT(4) --#define DEVCFG_TOUCH_UNKNOWN_5 BIT(5) --#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) -- --#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" -- --#define DEVCFG_SPI_MAX_FREQ(x) (((x) >> 1) & 0xf) // high bit = use high speed mode? --#define DEVCFG_SPI_MODE(x) (((x) >> 6) & 3) --#define DEVCFG_SPI_UNKNOWN_8(x) (((x) >> 8) & 0x3f) --#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat --#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) --#define DEVCFG_SPI_UNKNOWN_25 BIT(25) --#define DEVCFG_SPI_UNKNOWN_26 BIT(26) --#define DEVCFG_SPI_UNKNOWN_27 BIT(27) --#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this --#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? -- --struct ithc_device_config { // (Example values are from an SP7+.) -- u32 _unknown_00; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) -- u32 _unknown_04; // 04 = 0x00000000 -- u32 dma_buf_sizes; // 08 = 0x000a00ff -- u32 touch_cfg; // 0c = 0x0000001c -- u32 _unknown_10; // 10 = 0x0000001c -- u32 device_id; // 14 = 0x43495424 = "$TIC" -- u32 spi_config; // 18 = 0xfda00a2e -- u16 vendor_id; // 1c = 0x045e = Microsoft Corp. -- u16 product_id; // 1e = 0x0c1a -- u32 revision; // 20 = 0x00000001 -- u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) -- u32 _unknown_28; // 28 = 0x00000000 -- u32 fw_mode; // 2c = 0x00000000 (for fw update?) -- u32 _unknown_30; // 30 = 0x00000000 -- u32 _unknown_34; // 34 = 0x0404035e (u8,u8,u8,u8 = version?) -- u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) -- u32 _unknown_3c; // 3c = 0x00000002 --}; -- - void bitsl(__iomem u32 *reg, u32 mask, u32 val); - void bitsb(__iomem u8 *reg, u8 mask, u8 val); - #define bitsl_set(reg, x) bitsl(reg, x, x) - #define bitsb_set(reg, x) bitsb(reg, x, x) - int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); - int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); --int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode); -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); -+void ithc_set_ltr_idle(struct ithc *ithc); -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); - int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); - -diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h -index 028e55a4ec53..e90c38044432 100644 ---- a/drivers/hid/ithc/ithc.h -+++ b/drivers/hid/ithc/ithc.h -@@ -1,20 +1,19 @@ - /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ - --#include --#include --#include -+#include -+#include -+#include - #include -+#include - #include --#include -+#include - #include - #include --#include - #include - #include --#include -+#include -+#include - #include --#include --#include - - #define DEVNAME "ithc" - #define DEVFULLNAME "Intel Touch Host Controller" -@@ -27,10 +26,37 @@ - - #define NUM_RX_BUF 16 - -+// PCI device IDs: -+// Lakefield -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 -+// Tiger Lake -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 -+// Alder Lake -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 -+// Raptor Lake -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 -+// Meteor Lake -+#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a -+ - struct ithc; - - #include "ithc-regs.h" -+#include "ithc-hid.h" - #include "ithc-dma.h" -+#include "ithc-legacy.h" -+#include "ithc-quickspi.h" -+#include "ithc-debug.h" - - struct ithc { - char phys[32]; -@@ -38,30 +64,21 @@ struct ithc { - int irq; - struct task_struct *poll_thread; - -- struct pm_qos_request activity_qos; -- struct hrtimer activity_start_timer; -- struct hrtimer activity_end_timer; -- ktime_t last_rx_time; -- unsigned int cur_rx_seq_count; -- unsigned int cur_rx_seq_errors; -- -- struct hid_device *hid; -- bool hid_parse_done; -- wait_queue_head_t wait_hid_parse; -- wait_queue_head_t wait_hid_get_feature; -- struct mutex hid_get_feature_mutex; -- void *hid_get_feature_buf; -- size_t hid_get_feature_size; -- - struct ithc_registers __iomem *regs; - struct ithc_registers *prev_regs; // for debugging -- struct ithc_device_config config; - struct ithc_dma_rx dma_rx[2]; - struct ithc_dma_tx dma_tx; -+ struct ithc_hid hid; -+ -+ bool use_quickspi; -+ bool have_config; -+ u16 vendor_id; -+ u16 product_id; -+ u32 product_rev; -+ u32 max_rx_size; -+ u32 max_tx_size; -+ u32 legacy_touch_cfg; - }; - - int ithc_reset(struct ithc *ithc); --void ithc_set_active(struct ithc *ithc, unsigned int duration_us); --int ithc_debug_init(struct ithc *ithc); --void ithc_log_regs(struct ithc *ithc); - --- -2.44.0 - diff --git a/patches/6.8/0006-surface-sam.patch b/patches/6.8/0006-surface-sam.patch deleted file mode 100644 index fd1a2f895d..0000000000 --- a/patches/6.8/0006-surface-sam.patch +++ /dev/null @@ -1,1218 +0,0 @@ -From 973bf943acca4abdd932b5fdff032de0af07f96e Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 22 Oct 2023 14:57:11 +0200 -Subject: [PATCH] platform/surface: aggregator_registry: Add support for - Surface Laptop Go 3 - -Add SAM client device nodes for the Surface Laptop Go 3. It seems to use -the same SAM client devices as the Surface Laptop Go 1 and 2, so re-use -their node group. - -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index aeb3feae40ff..2bc4977037fc 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -367,6 +367,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { - /* Surface Laptop Go 2 */ - { "MSHW0290", (unsigned long)ssam_node_group_slg1 }, - -+ /* Surface Laptop Go 3 */ -+ { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, -+ - /* Surface Laptop Studio */ - { "MSHW0123", (unsigned long)ssam_node_group_sls }, - --- -2.44.0 - -From 7dedc84364f9c1fb73d271c859dce19b4a9644d6 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Mon, 20 Nov 2023 19:47:00 +0100 -Subject: [PATCH] platform/surface: aggregator_registry: Add support for - Surface Laptop Studio 2 - -Add SAM client device nodes for the Surface Laptop Studio 2 (SLS2). The -SLS2 is quite similar to the SLS1, but it does not provide the touchpad -as a SAM-HID device. Therefore, add a new node group for the SLS2 and -update the comments accordingly - -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - .../surface/surface_aggregator_registry.c | 25 ++++++++++++++++--- - 1 file changed, 21 insertions(+), 4 deletions(-) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 2bc4977037fc..26cb6229ad16 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -247,8 +247,8 @@ static const struct software_node *ssam_node_group_sl5[] = { - NULL, - }; - --/* Devices for Surface Laptop Studio. */ --static const struct software_node *ssam_node_group_sls[] = { -+/* Devices for Surface Laptop Studio 1. */ -+static const struct software_node *ssam_node_group_sls1[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -@@ -263,6 +263,20 @@ static const struct software_node *ssam_node_group_sls[] = { - NULL, - }; - -+/* Devices for Surface Laptop Studio 2. */ -+static const struct software_node *ssam_node_group_sls2[] = { -+ &ssam_node_root, -+ &ssam_node_bat_ac, -+ &ssam_node_bat_main, -+ &ssam_node_tmp_pprof, -+ &ssam_node_pos_tablet_switch, -+ &ssam_node_hid_sam_keyboard, -+ &ssam_node_hid_sam_penstash, -+ &ssam_node_hid_sam_sensors, -+ &ssam_node_hid_sam_ucm_ucsi, -+ NULL, -+}; -+ - /* Devices for Surface Laptop Go. */ - static const struct software_node *ssam_node_group_slg1[] = { - &ssam_node_root, -@@ -370,8 +384,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { - /* Surface Laptop Go 3 */ - { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, - -- /* Surface Laptop Studio */ -- { "MSHW0123", (unsigned long)ssam_node_group_sls }, -+ /* Surface Laptop Studio 1 */ -+ { "MSHW0123", (unsigned long)ssam_node_group_sls1 }, -+ -+ /* Surface Laptop Studio 2 */ -+ { "MSHW0360", (unsigned long)ssam_node_group_sls2 }, - - { }, - }; --- -2.44.0 - -From 96a7b3dd527f3e1b97e2d089a727c16cd5045aa5 Mon Sep 17 00:00:00 2001 -From: Ivor Wanders -Date: Mon, 18 Dec 2023 19:21:32 -0500 -Subject: [PATCH] platform/surface: aggregator_registry: add entry for fan - speed - -Add an entry for the fan speed function. -Add this new entry to the Surface Pro 9 group. - -Signed-off-by: Ivor Wanders -Link: https://github.com/linux-surface/kernel/pull/144 -Reviewed-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 26cb6229ad16..f02a933160ff 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = { - .parent = &ssam_node_root, - }; - -+/* Fan speed function. */ -+static const struct software_node ssam_node_fan_speed = { -+ .name = "ssam:01:05:01:01:01", -+ .parent = &ssam_node_root, -+}; -+ - /* Tablet-mode switch via KIP subsystem. */ - static const struct software_node ssam_node_kip_tablet_switch = { - .name = "ssam:01:0e:01:00:01", -@@ -319,6 +325,7 @@ static const struct software_node *ssam_node_group_sp9[] = { - &ssam_node_bat_ac, - &ssam_node_bat_main, - &ssam_node_tmp_pprof, -+ &ssam_node_fan_speed, - &ssam_node_pos_tablet_switch, - &ssam_node_hid_kip_keyboard, - &ssam_node_hid_kip_penstash, --- -2.44.0 - -From b4eb65349df9859f65aa9990c24c5036d35382da Mon Sep 17 00:00:00 2001 -From: Ivor Wanders -Date: Thu, 30 Nov 2023 20:20:24 -0500 -Subject: [PATCH] hwmon: add fan speed monitoring driver for Surface devices - -Adds a driver that provides read only access to the fan speed for Microsoft -Surface Pro devices. The fan speed is always regulated by the EC and cannot -be influenced directly. - -Signed-off-by: Ivor Wanders -Link: https://github.com/linux-surface/kernel/pull/144 -Patchset: surface-sam ---- - Documentation/hwmon/index.rst | 1 + - Documentation/hwmon/surface_fan.rst | 25 ++++++++ - MAINTAINERS | 8 +++ - drivers/hwmon/Kconfig | 13 ++++ - drivers/hwmon/Makefile | 1 + - drivers/hwmon/surface_fan.c | 93 +++++++++++++++++++++++++++++ - 6 files changed, 141 insertions(+) - create mode 100644 Documentation/hwmon/surface_fan.rst - create mode 100644 drivers/hwmon/surface_fan.c - -diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst -index c7ed1f73ac06..58be92e94a8d 100644 ---- a/Documentation/hwmon/index.rst -+++ b/Documentation/hwmon/index.rst -@@ -208,6 +208,7 @@ Hardware Monitoring Kernel Drivers - smsc47m1 - sparx5-temp - stpddc60 -+ surface_fan - sy7636a-hwmon - tc654 - tc74 -diff --git a/Documentation/hwmon/surface_fan.rst b/Documentation/hwmon/surface_fan.rst -new file mode 100644 -index 000000000000..07942574c4f0 ---- /dev/null -+++ b/Documentation/hwmon/surface_fan.rst -@@ -0,0 +1,25 @@ -+.. SPDX-License-Identifier: GPL-2.0-or-later -+ -+Kernel driver surface_fan -+========================= -+ -+Supported Devices: -+ -+ * Microsoft Surface Pro 9 -+ -+Author: Ivor Wanders -+ -+Description -+----------- -+ -+This provides monitoring of the fan found in some Microsoft Surface Pro devices, -+like the Surface Pro 9. The fan is always controlled by the onboard controller. -+ -+Sysfs interface -+--------------- -+ -+======================= ======= ========================================= -+Name Perm Description -+======================= ======= ========================================= -+``fan1_input`` RO Current fan speed in RPM. -+======================= ======= ========================================= -diff --git a/MAINTAINERS b/MAINTAINERS -index 1aabf1c15bb3..b6416cf3f022 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -14576,6 +14576,14 @@ F: Documentation/driver-api/surface_aggregator/clients/dtx.rst - F: drivers/platform/surface/surface_dtx.c - F: include/uapi/linux/surface_aggregator/dtx.h - -+MICROSOFT SURFACE SENSOR FAN DRIVER -+M: Maximilian Luz -+M: Ivor Wanders -+L: linux-hwmon@vger.kernel.org -+S: Maintained -+F: Documentation/hwmon/surface_fan.rst -+F: drivers/hwmon/surface_fan.c -+ - MICROSOFT SURFACE GPE LID SUPPORT DRIVER - M: Maximilian Luz - L: platform-driver-x86@vger.kernel.org -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index a608264da87d..e762f6138970 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -1994,6 +1994,19 @@ config SENSORS_SFCTEMP - This driver can also be built as a module. If so, the module - will be called sfctemp. - -+config SENSORS_SURFACE_FAN -+ tristate "Surface Fan Driver" -+ depends on SURFACE_AGGREGATOR -+ help -+ Driver that provides monitoring of the fan on Surface Pro devices that -+ have a fan, like the Surface Pro 9. -+ -+ This makes the fan's current speed accessible through the hwmon -+ system. It does not provide control over the fan, the firmware is -+ responsible for that, this driver merely provides monitoring. -+ -+ Select M or Y here, if you want to be able to read the fan's speed. -+ - config SENSORS_ADC128D818 - tristate "Texas Instruments ADC128D818" - depends on I2C -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 47be39af5c03..30cc90f40844 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -201,6 +201,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o - obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o - obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o - obj-$(CONFIG_SENSORS_STTS751) += stts751.o -+obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o - obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o - obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o - obj-$(CONFIG_SENSORS_TC74) += tc74.o -diff --git a/drivers/hwmon/surface_fan.c b/drivers/hwmon/surface_fan.c -new file mode 100644 -index 000000000000..7c2e3ae3eb40 ---- /dev/null -+++ b/drivers/hwmon/surface_fan.c -@@ -0,0 +1,93 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Surface Fan driver for Surface System Aggregator Module. It provides access -+ * to the fan's rpm through the hwmon system. -+ * -+ * Copyright (C) 2023 Ivor Wanders -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+// SSAM -+SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_fan_rpm_get, __le16, { -+ .target_category = SSAM_SSH_TC_FAN, -+ .command_id = 0x01, -+}); -+ -+// hwmon -+umode_t surface_fan_hwmon_is_visible(const void *drvdata, -+ enum hwmon_sensor_types type, u32 attr, -+ int channel) -+{ -+ return 0444; -+} -+ -+static int surface_fan_hwmon_read(struct device *dev, -+ enum hwmon_sensor_types type, u32 attr, -+ int channel, long *val) -+{ -+ struct ssam_device *sdev = dev_get_drvdata(dev); -+ int ret; -+ __le16 value; -+ -+ ret = __ssam_fan_rpm_get(sdev, &value); -+ if (ret) -+ return ret; -+ -+ *val = le16_to_cpu(value); -+ -+ return ret; -+} -+ -+static const struct hwmon_channel_info *const surface_fan_info[] = { -+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), -+ NULL -+}; -+ -+static const struct hwmon_ops surface_fan_hwmon_ops = { -+ .is_visible = surface_fan_hwmon_is_visible, -+ .read = surface_fan_hwmon_read, -+}; -+ -+static const struct hwmon_chip_info surface_fan_chip_info = { -+ .ops = &surface_fan_hwmon_ops, -+ .info = surface_fan_info, -+}; -+ -+static int surface_fan_probe(struct ssam_device *sdev) -+{ -+ struct device *hdev; -+ -+ hdev = devm_hwmon_device_register_with_info(&sdev->dev, -+ "surface_fan", sdev, -+ &surface_fan_chip_info, -+ NULL); -+ if (IS_ERR(hdev)) -+ return PTR_ERR(hdev); -+ -+ return 0; -+} -+ -+static const struct ssam_device_id ssam_fan_match[] = { -+ { SSAM_SDEV(FAN, SAM, 0x01, 0x01) }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(ssam, ssam_fan_match); -+ -+static struct ssam_device_driver surface_fan = { -+ .probe = surface_fan_probe, -+ .match_table = ssam_fan_match, -+ .driver = { -+ .name = "surface_fan", -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ }, -+}; -+module_ssam_device_driver(surface_fan); -+ -+MODULE_AUTHOR("Ivor Wanders "); -+MODULE_DESCRIPTION("Fan Driver for Surface System Aggregator Module"); -+MODULE_LICENSE("GPL"); --- -2.44.0 - -From 5c18bed9c7ad073b61e3c3686dc4bc1858f958dc Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 30 Dec 2023 18:07:54 +0100 -Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator - Module - -Some of the newer Microsoft Surface devices (such as the Surface Book -3 and Pro 9) have thermal sensors connected via the Surface Aggregator -Module (the embedded controller on those devices). Add a basic driver -to read out the temperature values of those sensors. - -Link: https://github.com/linux-surface/surface-aggregator-module/issues/59 -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/hwmon/Kconfig | 10 +++ - drivers/hwmon/Makefile | 1 + - drivers/hwmon/surface_temp.c | 165 +++++++++++++++++++++++++++++++++++ - 3 files changed, 176 insertions(+) - create mode 100644 drivers/hwmon/surface_temp.c - -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index e762f6138970..41261b49f8be 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -2007,6 +2007,16 @@ config SENSORS_SURFACE_FAN - - Select M or Y here, if you want to be able to read the fan's speed. - -+config SENSORS_SURFACE_TEMP -+ tristate "Microsoft Surface Thermal Sensor Driver" -+ depends on SURFACE_AGGREGATOR -+ help -+ Driver for monitoring thermal sensors connected via the Surface -+ Aggregator Module (embedded controller) on Microsoft Surface devices. -+ -+ This driver can also be built as a module. If so, the module -+ will be called surface_temp. -+ - config SENSORS_ADC128D818 - tristate "Texas Instruments ADC128D818" - depends on I2C -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 30cc90f40844..6644fd4598a4 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -202,6 +202,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o - obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o - obj-$(CONFIG_SENSORS_STTS751) += stts751.o - obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o -+obj-$(CONFIG_SENSORS_SURFACE_TEMP)+= surface_temp.o - obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o - obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o - obj-$(CONFIG_SENSORS_TC74) += tc74.o -diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c -new file mode 100644 -index 000000000000..48c3e826713f ---- /dev/null -+++ b/drivers/hwmon/surface_temp.c -@@ -0,0 +1,165 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Thermal sensor subsystem driver for Surface System Aggregator Module (SSAM). -+ * -+ * Copyright (C) 2022-2023 Maximilian Luz -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+/* -- SAM interface. -------------------------------------------------------- */ -+ -+SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, { -+ .target_category = SSAM_SSH_TC_TMP, -+ .command_id = 0x04, -+}); -+ -+SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, { -+ .target_category = SSAM_SSH_TC_TMP, -+ .command_id = 0x01, -+}); -+ -+static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors) -+{ -+ __le16 sensors_le; -+ int status; -+ -+ status = __ssam_tmp_get_available_sensors(sdev, &sensors_le); -+ if (status) -+ return status; -+ -+ *sensors = le16_to_cpu(sensors_le); -+ return 0; -+} -+ -+static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temperature) -+{ -+ __le16 temp_le; -+ int status; -+ -+ status = __ssam_tmp_get_temperature(sdev->ctrl, sdev->uid.target, iid, &temp_le); -+ if (status) -+ return status; -+ -+ /* Convert 1/10 °K to 1/1000 °C */ -+ *temperature = (le16_to_cpu(temp_le) - 2731) * 100L; -+ return 0; -+} -+ -+ -+/* -- Driver.---------------------------------------------------------------- */ -+ -+struct ssam_temp { -+ struct ssam_device *sdev; -+ s16 sensors; -+}; -+ -+static umode_t ssam_temp_hwmon_is_visible(const void *data, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ const struct ssam_temp *ssam_temp = data; -+ -+ if (!(ssam_temp->sensors & BIT(channel))) -+ return 0; -+ -+ return 0444; -+} -+ -+static int ssam_temp_hwmon_read(struct device *dev, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel, long *value) -+{ -+ const struct ssam_temp *ssam_temp = dev_get_drvdata(dev); -+ -+ return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value); -+} -+ -+static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = { -+ HWMON_CHANNEL_INFO(chip, -+ HWMON_C_REGISTER_TZ), -+ /* We have at most 16 thermal sensor channels. */ -+ HWMON_CHANNEL_INFO(temp, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT, -+ HWMON_T_INPUT), -+ NULL -+}; -+ -+static const struct hwmon_ops ssam_temp_hwmon_ops = { -+ .is_visible = ssam_temp_hwmon_is_visible, -+ .read = ssam_temp_hwmon_read, -+}; -+ -+static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = { -+ .ops = &ssam_temp_hwmon_ops, -+ .info = ssam_temp_hwmon_info, -+}; -+ -+static int ssam_temp_probe(struct ssam_device *sdev) -+{ -+ struct ssam_temp *ssam_temp; -+ struct device *hwmon_dev; -+ s16 sensors; -+ int status; -+ -+ status = ssam_tmp_get_available_sensors(sdev, &sensors); -+ if (status) -+ return status; -+ -+ ssam_temp = devm_kzalloc(&sdev->dev, sizeof(*ssam_temp), GFP_KERNEL); -+ if (!ssam_temp) -+ return -ENOMEM; -+ -+ ssam_temp->sdev = sdev; -+ ssam_temp->sensors = sensors; -+ -+ hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev, -+ "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, -+ NULL); -+ if (IS_ERR(hwmon_dev)) -+ return PTR_ERR(hwmon_dev); -+ -+ return 0; -+} -+ -+static const struct ssam_device_id ssam_temp_match[] = { -+ { SSAM_SDEV(TMP, SAM, 0x00, 0x02) }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(ssam, ssam_temp_match); -+ -+static struct ssam_device_driver ssam_temp = { -+ .probe = ssam_temp_probe, -+ .match_table = ssam_temp_match, -+ .driver = { -+ .name = "surface_temp", -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ }, -+}; -+module_ssam_device_driver(ssam_temp); -+ -+MODULE_AUTHOR("Maximilian Luz "); -+MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); -+MODULE_LICENSE("GPL"); --- -2.44.0 - -From 8b1e37ad9423a6fdf8a8b3bfb1e15aadefe136de Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 30 Dec 2023 18:12:23 +0100 -Subject: [PATCH] hwmon: surface_temp: Add support for sensor names - -The thermal subsystem of the Surface Aggregator Module allows us to -query the names of the respective thermal sensors. Forward those to -userspace. - -Signed-off-by: Ivor Wanders -Co-Developed-by: Maximilian Luz -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/hwmon/surface_temp.c | 113 +++++++++++++++++++++++++++++------ - 1 file changed, 96 insertions(+), 17 deletions(-) - -diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c -index 48c3e826713f..4c08926139db 100644 ---- a/drivers/hwmon/surface_temp.c -+++ b/drivers/hwmon/surface_temp.c -@@ -17,6 +17,27 @@ - - /* -- SAM interface. -------------------------------------------------------- */ - -+/* -+ * Available sensors are indicated by a 16-bit bitfield, where a 1 marks the -+ * presence of a sensor. So we have at most 16 possible sensors/channels. -+ */ -+#define SSAM_TMP_SENSOR_MAX_COUNT 16 -+ -+/* -+ * All names observed so far are 6 characters long, but there's only -+ * zeros after the name, so perhaps they can be longer. This number reflects -+ * the maximum zero-padded space observed in the returned buffer. -+ */ -+#define SSAM_TMP_SENSOR_NAME_LENGTH 18 -+ -+struct ssam_tmp_get_name_rsp { -+ __le16 unknown1; -+ char unknown2; -+ char name[SSAM_TMP_SENSOR_NAME_LENGTH]; -+} __packed; -+ -+static_assert(sizeof(struct ssam_tmp_get_name_rsp) == 21); -+ - SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, { - .target_category = SSAM_SSH_TC_TMP, - .command_id = 0x04, -@@ -27,6 +48,11 @@ SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, { - .command_id = 0x01, - }); - -+SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_name, struct ssam_tmp_get_name_rsp, { -+ .target_category = SSAM_SSH_TC_TMP, -+ .command_id = 0x0e, -+}); -+ - static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors) - { - __le16 sensors_le; -@@ -54,12 +80,37 @@ static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temp - return 0; - } - -+static int ssam_tmp_get_name(struct ssam_device *sdev, u8 iid, char *buf, size_t buf_len) -+{ -+ struct ssam_tmp_get_name_rsp name_rsp; -+ int status; -+ -+ status = __ssam_tmp_get_name(sdev->ctrl, sdev->uid.target, iid, &name_rsp); -+ if (status) -+ return status; -+ -+ /* -+ * This should not fail unless the name in the returned struct is not -+ * null-terminated or someone changed something in the struct -+ * definitions above, since our buffer and struct have the same -+ * capacity by design. So if this fails blow this up with a warning. -+ * Since the more likely cause is that the returned string isn't -+ * null-terminated, we might have received garbage (as opposed to just -+ * an incomplete string), so also fail the function. -+ */ -+ status = strscpy(buf, name_rsp.name, buf_len); -+ WARN_ON(status < 0); -+ -+ return status < 0 ? status : 0; -+} -+ - - /* -- Driver.---------------------------------------------------------------- */ - - struct ssam_temp { - struct ssam_device *sdev; - s16 sensors; -+ char names[SSAM_TMP_SENSOR_MAX_COUNT][SSAM_TMP_SENSOR_NAME_LENGTH]; - }; - - static umode_t ssam_temp_hwmon_is_visible(const void *data, -@@ -83,33 +134,47 @@ static int ssam_temp_hwmon_read(struct device *dev, - return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value); - } - -+static int ssam_temp_hwmon_read_string(struct device *dev, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel, const char **str) -+{ -+ const struct ssam_temp *ssam_temp = dev_get_drvdata(dev); -+ -+ *str = ssam_temp->names[channel]; -+ return 0; -+} -+ - static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = { - HWMON_CHANNEL_INFO(chip, - HWMON_C_REGISTER_TZ), -- /* We have at most 16 thermal sensor channels. */ -+ /* -+ * We have at most SSAM_TMP_SENSOR_MAX_COUNT = 16 thermal sensor -+ * channels. -+ */ - HWMON_CHANNEL_INFO(temp, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT, -- HWMON_T_INPUT), -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL), - NULL - }; - - static const struct hwmon_ops ssam_temp_hwmon_ops = { - .is_visible = ssam_temp_hwmon_is_visible, - .read = ssam_temp_hwmon_read, -+ .read_string = ssam_temp_hwmon_read_string, - }; - - static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = { -@@ -122,6 +187,7 @@ static int ssam_temp_probe(struct ssam_device *sdev) - struct ssam_temp *ssam_temp; - struct device *hwmon_dev; - s16 sensors; -+ int channel; - int status; - - status = ssam_tmp_get_available_sensors(sdev, &sensors); -@@ -135,6 +201,19 @@ static int ssam_temp_probe(struct ssam_device *sdev) - ssam_temp->sdev = sdev; - ssam_temp->sensors = sensors; - -+ /* Retrieve the name for each available sensor. */ -+ for (channel = 0; channel < SSAM_TMP_SENSOR_MAX_COUNT; channel++) -+ { -+ if (!(sensors & BIT(channel))) -+ continue; -+ -+ status = ssam_tmp_get_name(sdev, channel + 1, -+ ssam_temp->names[channel], -+ SSAM_TMP_SENSOR_NAME_LENGTH); -+ if (status) -+ return status; -+ } -+ - hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev, - "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, - NULL); --- -2.44.0 - -From 9b490a17f59518e59cf3c77c103bf5ddc52041a3 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 30 Dec 2023 18:21:12 +0100 -Subject: [PATCH] platform/surface: aggregator_registry: Add support for - thermal sensors on the Surface Pro 9 - -The Surface Pro 9 has thermal sensors connected via the Surface -Aggregator Module. Add a device node to support those. - -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index f02a933160ff..67686042e009 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = { - .parent = &ssam_node_root, - }; - -+/* Thermal sensors. */ -+static const struct software_node ssam_node_tmp_sensors = { -+ .name = "ssam:01:03:01:00:02", -+ .parent = &ssam_node_root, -+}; -+ - /* Fan speed function. */ - static const struct software_node ssam_node_fan_speed = { - .name = "ssam:01:05:01:01:01", -@@ -325,6 +331,7 @@ static const struct software_node *ssam_node_group_sp9[] = { - &ssam_node_bat_ac, - &ssam_node_bat_main, - &ssam_node_tmp_pprof, -+ &ssam_node_tmp_sensors, - &ssam_node_fan_speed, - &ssam_node_pos_tablet_switch, - &ssam_node_hid_kip_keyboard, --- -2.44.0 - -From ec0b680c0ce36ef6bffd682e10589cf5d8d467ae Mon Sep 17 00:00:00 2001 -From: Ivor Wanders -Date: Sat, 16 Dec 2023 15:56:39 -0500 -Subject: [PATCH] platform/surface: platform_profile: add fan profile switching - -Change naming from tmp to platform profile to clarify the module may -interact with both the TMP and FAN subystems. Add functionality that -switches the fan profile when the platform profile is changed. - -Signed-off-by: Ivor Wanders -Patchset: surface-sam ---- - .../surface/surface_aggregator_registry.c | 38 +++++--- - .../surface/surface_platform_profile.c | 86 ++++++++++++++++--- - 2 files changed, 100 insertions(+), 24 deletions(-) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 67686042e009..058b6654a91a 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -68,8 +68,8 @@ static const struct software_node ssam_node_bat_sb3base = { - .parent = &ssam_node_hub_base, - }; - --/* Platform profile / performance-mode device. */ --static const struct software_node ssam_node_tmp_pprof = { -+/* Platform profile / performance-mode device without a fan. */ -+static const struct software_node ssam_node_tmp_perf_profile = { - .name = "ssam:01:03:01:00:01", - .parent = &ssam_node_root, - }; -@@ -86,6 +86,20 @@ static const struct software_node ssam_node_fan_speed = { - .parent = &ssam_node_root, - }; - -+/* Platform profile / performance-mode device with a fan, such that -+ * the fan controller profile can also be switched. -+ */ -+static const struct property_entry ssam_node_tmp_perf_profile_has_fan[] = { -+ PROPERTY_ENTRY_BOOL("has_fan"), -+ { } -+}; -+ -+static const struct software_node ssam_node_tmp_perf_profile_with_fan = { -+ .name = "ssam:01:03:01:00:01", -+ .parent = &ssam_node_root, -+ .properties = ssam_node_tmp_perf_profile_has_fan, -+}; -+ - /* Tablet-mode switch via KIP subsystem. */ - static const struct software_node ssam_node_kip_tablet_switch = { - .name = "ssam:01:0e:01:00:01", -@@ -214,7 +228,7 @@ static const struct software_node ssam_node_pos_tablet_switch = { - */ - static const struct software_node *ssam_node_group_gen5[] = { - &ssam_node_root, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - NULL, - }; - -@@ -225,7 +239,7 @@ static const struct software_node *ssam_node_group_sb3[] = { - &ssam_node_bat_ac, - &ssam_node_bat_main, - &ssam_node_bat_sb3base, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - &ssam_node_bas_dtx, - &ssam_node_hid_base_keyboard, - &ssam_node_hid_base_touchpad, -@@ -239,7 +253,7 @@ static const struct software_node *ssam_node_group_sl3[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - &ssam_node_hid_main_keyboard, - &ssam_node_hid_main_touchpad, - &ssam_node_hid_main_iid5, -@@ -251,7 +265,7 @@ static const struct software_node *ssam_node_group_sl5[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - &ssam_node_hid_main_keyboard, - &ssam_node_hid_main_touchpad, - &ssam_node_hid_main_iid5, -@@ -264,7 +278,7 @@ static const struct software_node *ssam_node_group_sls1[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - &ssam_node_pos_tablet_switch, - &ssam_node_hid_sam_keyboard, - &ssam_node_hid_sam_penstash, -@@ -280,7 +294,7 @@ static const struct software_node *ssam_node_group_sls2[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - &ssam_node_pos_tablet_switch, - &ssam_node_hid_sam_keyboard, - &ssam_node_hid_sam_penstash, -@@ -294,7 +308,7 @@ static const struct software_node *ssam_node_group_slg1[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - NULL, - }; - -@@ -303,7 +317,7 @@ static const struct software_node *ssam_node_group_sp7[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - NULL, - }; - -@@ -313,7 +327,7 @@ static const struct software_node *ssam_node_group_sp8[] = { - &ssam_node_hub_kip, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile, - &ssam_node_kip_tablet_switch, - &ssam_node_hid_kip_keyboard, - &ssam_node_hid_kip_penstash, -@@ -330,7 +344,7 @@ static const struct software_node *ssam_node_group_sp9[] = { - &ssam_node_hub_kip, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile_with_fan, - &ssam_node_tmp_sensors, - &ssam_node_fan_speed, - &ssam_node_pos_tablet_switch, -diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c -index a5a3941b3f43..e54d0a8f7daa 100644 ---- a/drivers/platform/surface/surface_platform_profile.c -+++ b/drivers/platform/surface/surface_platform_profile.c -@@ -1,7 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0+ - /* - * Surface Platform Profile / Performance Mode driver for Surface System -- * Aggregator Module (thermal subsystem). -+ * Aggregator Module (thermal and fan subsystem). - * - * Copyright (C) 2021-2022 Maximilian Luz - */ -@@ -14,6 +14,7 @@ - - #include - -+// Enum for the platform performance profile sent to the TMP module. - enum ssam_tmp_profile { - SSAM_TMP_PROFILE_NORMAL = 1, - SSAM_TMP_PROFILE_BATTERY_SAVER = 2, -@@ -21,15 +22,26 @@ enum ssam_tmp_profile { - SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4, - }; - -+// Enum for the fan profile sent to the FAN module. This fan profile is -+// only sent to the EC if the 'has_fan' property is set. The integers are -+// not a typo, they differ from the performance profile indices. -+enum ssam_fan_profile { -+ SSAM_FAN_PROFILE_NORMAL = 2, -+ SSAM_FAN_PROFILE_BATTERY_SAVER = 1, -+ SSAM_FAN_PROFILE_BETTER_PERFORMANCE = 3, -+ SSAM_FAN_PROFILE_BEST_PERFORMANCE = 4, -+}; -+ - struct ssam_tmp_profile_info { - __le32 profile; - __le16 unknown1; - __le16 unknown2; - } __packed; - --struct ssam_tmp_profile_device { -+struct ssam_platform_profile_device { - struct ssam_device *sdev; - struct platform_profile_handler handler; -+ bool has_fan; - }; - - SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, { -@@ -42,6 +54,13 @@ SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, { - .command_id = 0x03, - }); - -+SSAM_DEFINE_SYNC_REQUEST_W(__ssam_fan_profile_set, char, { -+ .target_category = SSAM_SSH_TC_FAN, -+ .target_id = SSAM_SSH_TID_SAM, -+ .command_id = 0x0e, -+ .instance_id = 0x01, -+}); -+ - static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p) - { - struct ssam_tmp_profile_info info; -@@ -62,7 +81,14 @@ static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile - return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le); - } - --static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p) -+static int ssam_fan_profile_set(struct ssam_device *sdev, enum ssam_fan_profile p) -+{ -+ char profile = p; -+ -+ return ssam_retry(__ssam_fan_profile_set, sdev->ctrl, &profile); -+} -+ -+static int convert_ssam_tmp_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p) - { - switch (p) { - case SSAM_TMP_PROFILE_NORMAL: -@@ -83,7 +109,8 @@ static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profi - } - } - --static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p) -+ -+static int convert_profile_to_ssam_tmp(struct ssam_device *sdev, enum platform_profile_option p) - { - switch (p) { - case PLATFORM_PROFILE_LOW_POWER: -@@ -105,20 +132,42 @@ static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profi - } - } - -+static int convert_profile_to_ssam_fan(struct ssam_device *sdev, enum platform_profile_option p) -+{ -+ switch (p) { -+ case PLATFORM_PROFILE_LOW_POWER: -+ return SSAM_FAN_PROFILE_BATTERY_SAVER; -+ -+ case PLATFORM_PROFILE_BALANCED: -+ return SSAM_FAN_PROFILE_NORMAL; -+ -+ case PLATFORM_PROFILE_BALANCED_PERFORMANCE: -+ return SSAM_FAN_PROFILE_BETTER_PERFORMANCE; -+ -+ case PLATFORM_PROFILE_PERFORMANCE: -+ return SSAM_FAN_PROFILE_BEST_PERFORMANCE; -+ -+ default: -+ /* This should have already been caught by platform_profile_store(). */ -+ WARN(true, "unsupported platform profile"); -+ return -EOPNOTSUPP; -+ } -+} -+ - static int ssam_platform_profile_get(struct platform_profile_handler *pprof, - enum platform_profile_option *profile) - { -- struct ssam_tmp_profile_device *tpd; -+ struct ssam_platform_profile_device *tpd; - enum ssam_tmp_profile tp; - int status; - -- tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); -+ tpd = container_of(pprof, struct ssam_platform_profile_device, handler); - - status = ssam_tmp_profile_get(tpd->sdev, &tp); - if (status) - return status; - -- status = convert_ssam_to_profile(tpd->sdev, tp); -+ status = convert_ssam_tmp_to_profile(tpd->sdev, tp); - if (status < 0) - return status; - -@@ -129,21 +178,32 @@ static int ssam_platform_profile_get(struct platform_profile_handler *pprof, - static int ssam_platform_profile_set(struct platform_profile_handler *pprof, - enum platform_profile_option profile) - { -- struct ssam_tmp_profile_device *tpd; -+ struct ssam_platform_profile_device *tpd; - int tp; - -- tpd = container_of(pprof, struct ssam_tmp_profile_device, handler); -+ tpd = container_of(pprof, struct ssam_platform_profile_device, handler); -+ -+ tp = convert_profile_to_ssam_tmp(tpd->sdev, profile); -+ if (tp < 0) -+ return tp; - -- tp = convert_profile_to_ssam(tpd->sdev, profile); -+ tp = ssam_tmp_profile_set(tpd->sdev, tp); - if (tp < 0) - return tp; - -- return ssam_tmp_profile_set(tpd->sdev, tp); -+ if (tpd->has_fan) { -+ tp = convert_profile_to_ssam_fan(tpd->sdev, profile); -+ if (tp < 0) -+ return tp; -+ tp = ssam_fan_profile_set(tpd->sdev, tp); -+ } -+ -+ return tp; - } - - static int surface_platform_profile_probe(struct ssam_device *sdev) - { -- struct ssam_tmp_profile_device *tpd; -+ struct ssam_platform_profile_device *tpd; - - tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL); - if (!tpd) -@@ -154,6 +214,8 @@ static int surface_platform_profile_probe(struct ssam_device *sdev) - tpd->handler.profile_get = ssam_platform_profile_get; - tpd->handler.profile_set = ssam_platform_profile_set; - -+ tpd->has_fan = device_property_read_bool(&sdev->dev, "has_fan"); -+ - set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices); - set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices); - set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices); --- -2.44.0 - -From 63781a056a0f06d5cc38d7755e0753c7ec08c51c Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Fri, 19 Apr 2024 20:41:47 +0200 -Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is - destroyed in probe - -There is a small window in ssam_serial_hub_probe() where the controller -is initialized but has not been started yet. Specifically, between -ssam_controller_init() and ssam_controller_start(). Any failure in this -window, for example caused by a failure of serdev_device_open(), -currently results in an incorrect warning being emitted. - -In particular, any failure in this window results in the controller -being destroyed via ssam_controller_destroy(). This function checks the -state of the controller and, in an attempt to validate that the -controller has been cleanly shut down before we try and deallocate any -resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. - -However, since we have only just initialized the controller and have not -yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this -is the only point at which the controller has this state, as it will -change after we start the controller with ssam_controller_start() and -never revert back. Further, at this point no communication has taken -place and the sender and receiver threads have not been started yet (and -we may not even have an open serdev device either). - -Therefore, it is perfectly safe to call ssam_controller_destroy() with a -state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the -warning currently being emitted is incorrect. Fix it by extending the -check. - -Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") -Signed-off-by: Maximilian Luz ---- - drivers/platform/surface/aggregator/controller.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c -index 7fc602e01487..7e89f547999b 100644 ---- a/drivers/platform/surface/aggregator/controller.c -+++ b/drivers/platform/surface/aggregator/controller.c -@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) - if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) - return; - -- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); -+ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && -+ ctrl->state != SSAM_CONTROLLER_INITIALIZED); - - /* - * Note: New events could still have been received after the previous --- -2.44.0 - diff --git a/patches/6.8/0007-surface-sam-over-hid.patch b/patches/6.8/0007-surface-sam-over-hid.patch deleted file mode 100644 index 635d87df0c..0000000000 --- a/patches/6.8/0007-surface-sam-over-hid.patch +++ /dev/null @@ -1,335 +0,0 @@ -From 95b66fb97652988a7b4be5bb1deaa625e1bb3c3f Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 25 Jul 2020 17:19:53 +0200 -Subject: [PATCH] i2c: acpi: Implement RawBytes read access - -Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C -device via a generic serial bus operation region and RawBytes read -access. On the Surface Book 1, this access is required to turn on (and -off) the discrete GPU. - -Multiple things are to note here: - -a) The RawBytes access is device/driver dependent. The ACPI - specification states: - - > Raw accesses assume that the writer has knowledge of the bus that - > the access is made over and the device that is being accessed. The - > protocol may only ensure that the buffer is transmitted to the - > appropriate driver, but the driver must be able to interpret the - > buffer to communicate to a register. - - Thus this implementation may likely not work on other devices - accessing I2C via the RawBytes accessor type. - -b) The MSHW0030 I2C device is an HID-over-I2C device which seems to - serve multiple functions: - - 1. It is the main access point for the legacy-type Surface Aggregator - Module (also referred to as SAM-over-HID, as opposed to the newer - SAM-over-SSH/UART). It has currently not been determined on how - support for the legacy SAM should be implemented. Likely via a - custom HID driver. - - 2. It seems to serve as the HID device for the Integrated Sensor Hub. - This might complicate matters with regards to implementing a - SAM-over-HID driver required by legacy SAM. - -In light of this, the simplest approach has been chosen for now. -However, it may make more sense regarding breakage and compatibility to -either provide functionality for replacing or enhancing the default -operation region handler via some additional API functions, or even to -completely blacklist MSHW0030 from the I2C core and provide a custom -driver for it. - -Replacing/enhancing the default operation region handler would, however, -either require some sort of secondary driver and access point for it, -from which the new API functions would be called and the new handler -(part) would be installed, or hard-coding them via some sort of -quirk-like interface into the I2C core. - -Signed-off-by: Maximilian Luz -Patchset: surface-sam-over-hid ---- - drivers/i2c/i2c-core-acpi.c | 35 +++++++++++++++++++++++++++++++++++ - 1 file changed, 35 insertions(+) - -diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index d6037a328669..a290ebc77aea 100644 ---- a/drivers/i2c/i2c-core-acpi.c -+++ b/drivers/i2c/i2c-core-acpi.c -@@ -628,6 +628,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, - return (ret == 1) ? 0 : -EIO; - } - -+static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, -+ u8 *data, u8 data_len) -+{ -+ struct i2c_msg msgs[1]; -+ int ret = AE_OK; -+ -+ msgs[0].addr = client->addr; -+ msgs[0].flags = client->flags; -+ msgs[0].len = data_len + 1; -+ msgs[0].buf = data; -+ -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ -+ if (ret < 0) { -+ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* 1 transfer must have completed successfully */ -+ return (ret == 1) ? 0 : -EIO; -+} -+ - static acpi_status - i2c_acpi_space_handler(u32 function, acpi_physical_address command, - u32 bits, u64 *value64, -@@ -729,6 +751,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, - } - break; - -+ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: -+ if (action == ACPI_READ) { -+ dev_warn(&adapter->dev, -+ "protocol 0x%02x not supported for client 0x%02x\n", -+ accessor_type, client->addr); -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } else { -+ status = acpi_gsb_i2c_write_raw_bytes(client, -+ gsb->data, info->access_length); -+ } -+ break; -+ - default: - dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", - accessor_type, client->addr); --- -2.44.0 - -From 2b86ac312b956799265cdd1411d305cd2dcaf6db Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 13 Feb 2021 16:41:18 +0100 -Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch - -Add driver exposing the discrete GPU power-switch of the Microsoft -Surface Book 1 to user-space. - -On the Surface Book 1, the dGPU power is controlled via the Surface -System Aggregator Module (SAM). The specific SAM-over-HID command for -this is exposed via ACPI. This module provides a simple driver exposing -the ACPI call via a sysfs parameter to user-space, so that users can -easily power-on/-off the dGPU. - -Patchset: surface-sam-over-hid ---- - drivers/platform/surface/Kconfig | 7 + - drivers/platform/surface/Makefile | 1 + - .../surface/surfacebook1_dgpu_switch.c | 162 ++++++++++++++++++ - 3 files changed, 170 insertions(+) - create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c - -diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index b629e82af97c..68656e8f309e 100644 ---- a/drivers/platform/surface/Kconfig -+++ b/drivers/platform/surface/Kconfig -@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH - Select M or Y here, if you want to provide tablet-mode switch input - events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. - -+config SURFACE_BOOK1_DGPU_SWITCH -+ tristate "Surface Book 1 dGPU Switch Driver" -+ depends on SYSFS -+ help -+ This driver provides a sysfs switch to set the power-state of the -+ discrete GPU found on the Microsoft Surface Book 1. -+ - config SURFACE_DTX - tristate "Surface DTX (Detachment System) Driver" - depends on SURFACE_AGGREGATOR -diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 ---- a/drivers/platform/surface/Makefile -+++ b/drivers/platform/surface/Makefile -@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o - obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o - obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o - obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o -+obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o - obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o - obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o - obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o -diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c -new file mode 100644 -index 000000000000..8b816ed8f35c ---- /dev/null -+++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c -@@ -0,0 +1,162 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include -+#include -+#include -+#include -+ -+ -+#ifdef pr_fmt -+#undef pr_fmt -+#endif -+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ -+ -+ -+static const guid_t dgpu_sw_guid = GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, -+ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); -+ -+#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" -+#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" -+#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" -+ -+ -+static int sb1_dgpu_sw_dsmcall(void) -+{ -+ union acpi_object *ret; -+ acpi_handle handle; -+ acpi_status status; -+ -+ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); -+ if (status) -+ return -EINVAL; -+ -+ ret = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); -+ if (!ret) -+ return -EINVAL; -+ -+ ACPI_FREE(ret); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgon(void) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); -+ if (status) { -+ pr_err("failed to run HGON: %d\n", status); -+ return -EINVAL; -+ } -+ -+ if (buf.pointer) -+ ACPI_FREE(buf.pointer); -+ -+ pr_info("turned-on dGPU via HGON\n"); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgof(void) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); -+ if (status) { -+ pr_err("failed to run HGOF: %d\n", status); -+ return -EINVAL; -+ } -+ -+ if (buf.pointer) -+ ACPI_FREE(buf.pointer); -+ -+ pr_info("turned-off dGPU via HGOF\n"); -+ return 0; -+} -+ -+ -+static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int status, value; -+ -+ status = kstrtoint(buf, 0, &value); -+ if (status < 0) -+ return status; -+ -+ if (value != 1) -+ return -EINVAL; -+ -+ status = sb1_dgpu_sw_dsmcall(); -+ -+ return status < 0 ? status : len; -+} -+ -+static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool power; -+ int status; -+ -+ status = kstrtobool(buf, &power); -+ if (status < 0) -+ return status; -+ -+ if (power) -+ status = sb1_dgpu_sw_hgon(); -+ else -+ status = sb1_dgpu_sw_hgof(); -+ -+ return status < 0 ? status : len; -+} -+ -+static DEVICE_ATTR_WO(dgpu_dsmcall); -+static DEVICE_ATTR_WO(dgpu_power); -+ -+static struct attribute *sb1_dgpu_sw_attrs[] = { -+ &dev_attr_dgpu_dsmcall.attr, -+ &dev_attr_dgpu_power.attr, -+ NULL, -+}; -+ -+static const struct attribute_group sb1_dgpu_sw_attr_group = { -+ .attrs = sb1_dgpu_sw_attrs, -+}; -+ -+ -+static int sb1_dgpu_sw_probe(struct platform_device *pdev) -+{ -+ return sysfs_create_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); -+} -+ -+static int sb1_dgpu_sw_remove(struct platform_device *pdev) -+{ -+ sysfs_remove_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); -+ return 0; -+} -+ -+/* -+ * The dGPU power seems to be actually handled by MSHW0040. However, that is -+ * also the power-/volume-button device with a mainline driver. So let's use -+ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. -+ */ -+static const struct acpi_device_id sb1_dgpu_sw_match[] = { -+ { "MSHW0041", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); -+ -+static struct platform_driver sb1_dgpu_sw = { -+ .probe = sb1_dgpu_sw_probe, -+ .remove = sb1_dgpu_sw_remove, -+ .driver = { -+ .name = "surfacebook1_dgpu_switch", -+ .acpi_match_table = sb1_dgpu_sw_match, -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ }, -+}; -+module_platform_driver(sb1_dgpu_sw); -+ -+MODULE_AUTHOR("Maximilian Luz "); -+MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); -+MODULE_LICENSE("GPL"); --- -2.44.0 - diff --git a/patches/6.8/0008-surface-button.patch b/patches/6.8/0008-surface-button.patch deleted file mode 100644 index af5086f37e..0000000000 --- a/patches/6.8/0008-surface-button.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 3584a6c1791dc9c9b9c3ee846621571cbfabe37e Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Tue, 5 Oct 2021 00:05:09 +1100 -Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices - -The power button on the AMD variant of the Surface Laptop uses the -same MSHW0040 device ID as the 5th and later generation of Surface -devices, however they report 0 for their OEM platform revision. As the -_DSM does not exist on the devices requiring special casing, check for -the existance of the _DSM to determine if soc_button_array should be -loaded. - -Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") -Co-developed-by: Maximilian Luz - -Signed-off-by: Sachi King -Patchset: surface-button ---- - drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- - 1 file changed, 8 insertions(+), 25 deletions(-) - -diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index f6d060377d18..b8603f74eb28 100644 ---- a/drivers/input/misc/soc_button_array.c -+++ b/drivers/input/misc/soc_button_array.c -@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { - * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned - * devices use MSHW0040 for power and volume buttons, however the way they - * have to be addressed differs. Make sure that we only load this drivers -- * for the correct devices by checking the OEM Platform Revision provided by -- * the _DSM method. -+ * for the correct devices by checking if the OEM Platform Revision DSM call -+ * exists. - */ - #define MSHW0040_DSM_REVISION 0x01 - #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision -@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = - static int soc_device_check_MSHW0040(struct device *dev) - { - acpi_handle handle = ACPI_HANDLE(dev); -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, NULL, -- ACPI_TYPE_INTEGER); -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- /* -- * If the revision is zero here, the _DSM evaluation has failed. This -- * indicates that we have a Pro 4 or Book 1 and this driver should not -- * be used. -- */ -- if (oem_platform_rev == 0) -- return -ENODEV; -+ bool exists; - -- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); -+ // check if OEM platform revision DSM call exists -+ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - -- return 0; -+ return exists ? 0 : -ENODEV; - } - - /* --- -2.44.0 - -From c26bb1d0af0fe40be270d203d6aaeab28dd04a10 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Tue, 5 Oct 2021 00:22:57 +1100 -Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd - variant - -The AMD variant of the Surface Laptop report 0 for their OEM platform -revision. The Surface devices that require the surfacepro3_button -driver do not have the _DSM that gets the OEM platform revision. If the -method does not exist, load surfacepro3_button. - -Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") -Co-developed-by: Maximilian Luz - -Signed-off-by: Sachi King -Patchset: surface-button ---- - drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- - 1 file changed, 6 insertions(+), 24 deletions(-) - -diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 ---- a/drivers/platform/surface/surfacepro3_button.c -+++ b/drivers/platform/surface/surfacepro3_button.c -@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) - /* - * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device - * ID (MSHW0040) for the power/volume buttons. Make sure this is the right -- * device by checking for the _DSM method and OEM Platform Revision. -+ * device by checking for the _DSM method and OEM Platform Revision DSM -+ * function. - * - * Returns true if the driver should bind to this device, i.e. the device is - * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. -@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) - static bool surface_button_check_MSHW0040(struct acpi_device *dev) - { - acpi_handle handle = dev->handle; -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, -- NULL, ACPI_TYPE_INTEGER); -- -- /* -- * If evaluating the _DSM fails, the method is not present. This means -- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we -- * should use this driver. We use revision 0 indicating it is -- * unavailable. -- */ -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); - -- return oem_platform_rev == 0; -+ // make sure that OEM platform revision DSM call does not exist -+ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - } - - --- -2.44.0 - diff --git a/patches/6.8/0009-surface-typecover.patch b/patches/6.8/0009-surface-typecover.patch deleted file mode 100644 index bd6e4df977..0000000000 --- a/patches/6.8/0009-surface-typecover.patch +++ /dev/null @@ -1,573 +0,0 @@ -From b3fac417611f5bb4ae2a9bc9e828dacfe4418fbf Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 18 Feb 2023 01:02:49 +0100 -Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 - Type-Cover - -The touchpad on the Type-Cover of the Surface Go 3 is sometimes not -being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this -issue. - -More specifically, the device in question is a fairly standard modern -touchpad with pointer and touchpad input modes. During setup, the device -needs to be switched from pointer- to touchpad-mode (which is done in -hid-multitouch) to fully utilize it as intended. Unfortunately, however, -this seems to occasionally fail silently, leaving the device in -pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. - -Link: https://github.com/linux-surface/linux-surface/issues/1059 -Signed-off-by: Maximilian Luz -Patchset: surface-typecover ---- - drivers/usb/core/quirks.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index b4783574b8e6..360970620589 100644 ---- a/drivers/usb/core/quirks.c -+++ b/drivers/usb/core/quirks.c -@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { - /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ - { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, - -+ /* Microsoft Surface Go 3 Type-Cover */ -+ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, -+ - /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ - { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, - --- -2.44.0 - -From bf5167d418b660e321368222505a97d9f1ed68b4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 5 Nov 2020 13:09:45 +0100 -Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when - suspending - -The Type Cover for Microsoft Surface devices supports a special usb -control request to disable or enable the built-in keyboard backlight. -On Windows, this request happens when putting the device into suspend or -resuming it, without it the backlight of the Type Cover will remain -enabled for some time even though the computer is suspended, which looks -weird to the user. - -So add support for this special usb control request to hid-multitouch, -which is the driver that's handling the Type Cover. - -The reason we have to use a pm_notifier for this instead of the usual -suspend/resume methods is that those won't get called in case the usb -device is already autosuspended. - -Also, if the device is autosuspended, we have to briefly autoresume it -in order to send the request. Doing that should be fine, the usb-core -driver does something similar during suspend inside choose_wakeup(). - -To make sure we don't send that request to every device but only to -devices which support it, add a new quirk -MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk -is only enabled for the usb id of the Surface Pro 2017 Type Cover, which -is where I confirmed that it's working. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- - 1 file changed, 98 insertions(+), 2 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 3e91e4d6ba6f..45b7884c97f0 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -34,7 +34,10 @@ - #include - #include - #include -+#include - #include -+#include -+#include - #include - #include - #include -@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); - MODULE_LICENSE("GPL"); - - #include "hid-ids.h" -+#include "usbhid/usbhid.h" - - /* quirks to control the device */ - #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) -@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 - - #define MT_BUTTONTYPE_CLICKPAD 0 - -+#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+ - enum latency_mode { - HID_LATENCY_NORMAL = 0, - HID_LATENCY_HIGH = 1, -@@ -169,6 +176,8 @@ struct mt_device { - - struct list_head applications; - struct list_head reports; -+ -+ struct notifier_block pm_notifier; - }; - - static void mt_post_parse_default_settings(struct mt_device *td, -@@ -213,6 +222,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_GOOGLE 0x0111 - #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 - #define MT_CLS_SMART_TECH 0x0113 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 - - #define MT_DEFAULT_MAXCONTACT 10 - #define MT_MAX_MAXCONTACT 250 -@@ -397,6 +407,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_SEPARATE_APP_REPORT, - }, -+ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, -+ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | -+ MT_QUIRK_ALWAYS_VALID | -+ MT_QUIRK_IGNORE_DUPLICATES | -+ MT_QUIRK_HOVERING | -+ MT_QUIRK_CONTACT_CNT_ACCURATE | -+ MT_QUIRK_STICKY_FINGERS | -+ MT_QUIRK_WIN8_PTP_BUTTONS, -+ .export_all_inputs = true -+ }, - { } - }; - -@@ -1721,6 +1741,69 @@ static void mt_expired_timeout(struct timer_list *t) - clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); - } - -+static void get_type_cover_backlight_field(struct hid_device *hdev, -+ struct hid_field **field) -+{ -+ struct hid_report_enum *rep_enum; -+ struct hid_report *rep; -+ struct hid_field *cur_field; -+ int i, j; -+ -+ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; -+ list_for_each_entry(rep, &rep_enum->report_list, list) { -+ for (i = 0; i < rep->maxfield; i++) { -+ cur_field = rep->field[i]; -+ -+ for (j = 0; j < cur_field->maxusage; j++) { -+ if (cur_field->usage[j].hid -+ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { -+ *field = cur_field; -+ return; -+ } -+ } -+ } -+ } -+} -+ -+static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) -+{ -+ struct usb_device *udev = hid_to_usb_dev(hdev); -+ struct hid_field *field = NULL; -+ -+ /* Wake up the device in case it's already suspended */ -+ pm_runtime_get_sync(&udev->dev); -+ -+ get_type_cover_backlight_field(hdev, &field); -+ if (!field) { -+ hid_err(hdev, "couldn't find backlight field\n"); -+ goto out; -+ } -+ -+ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; -+ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); -+ -+out: -+ pm_runtime_put_sync(&udev->dev); -+} -+ -+static int mt_pm_notifier(struct notifier_block *notifier, -+ unsigned long pm_event, -+ void *unused) -+{ -+ struct mt_device *td = -+ container_of(notifier, struct mt_device, pm_notifier); -+ struct hid_device *hdev = td->hdev; -+ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { -+ if (pm_event == PM_SUSPEND_PREPARE) -+ update_keyboard_backlight(hdev, 0); -+ else if (pm_event == PM_POST_SUSPEND) -+ update_keyboard_backlight(hdev, 1); -+ } -+ -+ return NOTIFY_DONE; -+} -+ - static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - { - int ret, i; -@@ -1744,6 +1827,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; - hid_set_drvdata(hdev, td); - -+ td->pm_notifier.notifier_call = mt_pm_notifier; -+ register_pm_notifier(&td->pm_notifier); -+ - INIT_LIST_HEAD(&td->applications); - INIT_LIST_HEAD(&td->reports); - -@@ -1782,15 +1868,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - timer_setup(&td->release_timer, mt_expired_timeout, 0); - - ret = hid_parse(hdev); -- if (ret != 0) -+ if (ret != 0) { -+ unregister_pm_notifier(&td->pm_notifier); - return ret; -+ } - - if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) - mt_fix_const_fields(hdev, HID_DG_CONTACTID); - - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); -- if (ret) -+ if (ret) { -+ unregister_pm_notifier(&td->pm_notifier); - return ret; -+ } - - ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); - if (ret) -@@ -1840,6 +1930,7 @@ static void mt_remove(struct hid_device *hdev) - { - struct mt_device *td = hid_get_drvdata(hdev); - -+ unregister_pm_notifier(&td->pm_notifier); - del_timer_sync(&td->release_timer); - - sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2230,6 +2321,11 @@ static const struct hid_device_id mt_devices[] = { - MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, - USB_DEVICE_ID_XIROKU_CSR2) }, - -+ /* Microsoft Surface type cover */ -+ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, -+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, -+ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, -+ - /* Google MT devices */ - { .driver_data = MT_CLS_GOOGLE, - HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, --- -2.44.0 - -From dda4ca6e0248ae5acf3aaf78ee00e613f4e04bad Mon Sep 17 00:00:00 2001 -From: PJungkamp -Date: Fri, 25 Feb 2022 12:04:25 +0100 -Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet - switch - -The Surface Pro Type Cover has several non standard HID usages in it's -hid report descriptor. -I noticed that, upon folding the typecover back, a vendor specific range -of 4 32 bit integer hid usages is transmitted. -Only the first byte of the message seems to convey reliable information -about the keyboard state. - -0x22 => Normal (keys enabled) -0x33 => Folded back (keys disabled) -0x53 => Rotated left/right side up (keys disabled) -0x13 => Cover closed (keys disabled) -0x43 => Folded back and Tablet upside down (keys disabled) -This list may not be exhaustive. - -The tablet mode switch will be disabled for a value of 0x22 and enabled -on any other value. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ - 1 file changed, 122 insertions(+), 26 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 45b7884c97f0..f8978b405aca 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); - #define MT_BUTTONTYPE_CLICKPAD 0 - - #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 -+#define MS_TYPE_COVER_APPLICATION 0xff050050 - - enum latency_mode { - HID_LATENCY_NORMAL = 0, -@@ -409,6 +412,7 @@ static const struct mt_class mt_classes[] = { - }, - { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, - .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | -+ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_IGNORE_DUPLICATES | - MT_QUIRK_HOVERING | -@@ -1390,6 +1394,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - field->application != HID_CP_CONSUMER_CONTROL && - field->application != HID_GD_WIRELESS_RADIO_CTLS && - field->application != HID_GD_SYSTEM_MULTIAXIS && -+ !(field->application == MS_TYPE_COVER_APPLICATION && -+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && - !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && - application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) - return -1; -@@ -1417,6 +1424,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - return 1; - } - -+ /* -+ * The Microsoft Surface Pro Typecover has a non-standard HID -+ * tablet mode switch on a vendor specific usage page with vendor -+ * specific usage. -+ */ -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ usage->type = EV_SW; -+ usage->code = SW_TABLET_MODE; -+ *max = SW_MAX; -+ *bit = hi->input->swbit; -+ return 1; -+ } -+ - if (rdata->is_mt_collection) - return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, - application); -@@ -1438,6 +1460,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, - { - struct mt_device *td = hid_get_drvdata(hdev); - struct mt_report_data *rdata; -+ struct input_dev *input; - - rdata = mt_find_report_data(td, field->report); - if (rdata && rdata->is_mt_collection) { -@@ -1445,6 +1468,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, - return -1; - } - -+ /* -+ * We own an input device which acts as a tablet mode switch for -+ * the Surface Pro Typecover. -+ */ -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ input = hi->input; -+ input_set_capability(input, EV_SW, SW_TABLET_MODE); -+ input_report_switch(input, SW_TABLET_MODE, 0); -+ return -1; -+ } -+ - /* let hid-core decide for the others */ - return 0; - } -@@ -1454,11 +1490,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, - { - struct mt_device *td = hid_get_drvdata(hid); - struct mt_report_data *rdata; -+ struct input_dev *input; - - rdata = mt_find_report_data(td, field->report); - if (rdata && rdata->is_mt_collection) - return mt_touch_event(hid, field, usage, value); - -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ input = field->hidinput->input; -+ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); -+ input_sync(input); -+ return 1; -+ } -+ - return 0; - } - -@@ -1611,6 +1657,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) - app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; - } - -+static int get_type_cover_field(struct hid_report_enum *rep_enum, -+ struct hid_field **field, int usage) -+{ -+ struct hid_report *rep; -+ struct hid_field *cur_field; -+ int i, j; -+ -+ list_for_each_entry(rep, &rep_enum->report_list, list) { -+ for (i = 0; i < rep->maxfield; i++) { -+ cur_field = rep->field[i]; -+ if (cur_field->application != MS_TYPE_COVER_APPLICATION) -+ continue; -+ for (j = 0; j < cur_field->maxusage; j++) { -+ if (cur_field->usage[j].hid == usage) { -+ *field = cur_field; -+ return true; -+ } -+ } -+ } -+ } -+ return false; -+} -+ -+static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) -+{ -+ struct hid_field *field; -+ -+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], -+ &field, -+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { -+ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); -+ } else { -+ hid_err(hdev, "couldn't find tablet mode field\n"); -+ } -+} -+ - static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) - { - struct mt_device *td = hid_get_drvdata(hdev); -@@ -1659,6 +1741,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); - break; -+ case MS_TYPE_COVER_APPLICATION: -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { -+ suffix = "Tablet Mode Switch"; -+ request_type_cover_tablet_mode_switch(hdev); -+ break; -+ } -+ fallthrough; - default: - suffix = "UNKNOWN"; - break; -@@ -1741,30 +1830,6 @@ static void mt_expired_timeout(struct timer_list *t) - clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); - } - --static void get_type_cover_backlight_field(struct hid_device *hdev, -- struct hid_field **field) --{ -- struct hid_report_enum *rep_enum; -- struct hid_report *rep; -- struct hid_field *cur_field; -- int i, j; -- -- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; -- list_for_each_entry(rep, &rep_enum->report_list, list) { -- for (i = 0; i < rep->maxfield; i++) { -- cur_field = rep->field[i]; -- -- for (j = 0; j < cur_field->maxusage; j++) { -- if (cur_field->usage[j].hid -- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { -- *field = cur_field; -- return; -- } -- } -- } -- } --} -- - static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) - { - struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1773,8 +1838,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) - /* Wake up the device in case it's already suspended */ - pm_runtime_get_sync(&udev->dev); - -- get_type_cover_backlight_field(hdev, &field); -- if (!field) { -+ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], -+ &field, -+ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { - hid_err(hdev, "couldn't find backlight field\n"); - goto out; - } -@@ -1908,13 +1974,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) - - static int mt_reset_resume(struct hid_device *hdev) - { -+ struct mt_device *td = hid_get_drvdata(hdev); -+ - mt_release_contacts(hdev); - mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); -+ -+ /* Request an update on the typecover folding state on resume -+ * after reset. -+ */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) -+ request_type_cover_tablet_mode_switch(hdev); -+ - return 0; - } - - static int mt_resume(struct hid_device *hdev) - { -+ struct mt_device *td = hid_get_drvdata(hdev); -+ - /* Some Elan legacy devices require SET_IDLE to be set on resume. - * It should be safe to send it to other devices too. - * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1923,12 +2000,31 @@ static int mt_resume(struct hid_device *hdev) - - mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); - -+ /* Request an update on the typecover folding state on resume. */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) -+ request_type_cover_tablet_mode_switch(hdev); -+ - return 0; - } - - static void mt_remove(struct hid_device *hdev) - { - struct mt_device *td = hid_get_drvdata(hdev); -+ struct hid_field *field; -+ struct input_dev *input; -+ -+ /* Reset tablet mode switch on disconnect. */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { -+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], -+ &field, -+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { -+ input = field->hidinput->input; -+ input_report_switch(input, SW_TABLET_MODE, 0); -+ input_sync(input); -+ } else { -+ hid_err(hdev, "couldn't find tablet mode field\n"); -+ } -+ } - - unregister_pm_notifier(&td->pm_notifier); - del_timer_sync(&td->release_timer); --- -2.44.0 - diff --git a/patches/6.8/0010-surface-shutdown.patch b/patches/6.8/0010-surface-shutdown.patch deleted file mode 100644 index 14f012042c..0000000000 --- a/patches/6.8/0010-surface-shutdown.patch +++ /dev/null @@ -1,97 +0,0 @@ -From aa49dc59b192cc038ca789ac70215d7492f043cb Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod - -Work around buggy EFI firmware: On some Microsoft Surface devices -(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with -EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the -system down, it returns and the system stays on. - -It turns out that this only happens after PCI shutdown callbacks ran for -specific devices. Excluding those devices from the shutdown process -makes the ResetSystem call work as expected. - -TODO: Maybe we can find a better way or the root cause of this? - -Not-Signed-off-by: Maximilian Luz -Patchset: surface-shutdown ---- - drivers/pci/pci-driver.c | 3 +++ - drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ - include/linux/pci.h | 1 + - 3 files changed, 40 insertions(+) - -diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 51ec9e7e784f..40554890d721 100644 ---- a/drivers/pci/pci-driver.c -+++ b/drivers/pci/pci-driver.c -@@ -507,6 +507,9 @@ static void pci_device_shutdown(struct device *dev) - struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = pci_dev->driver; - -+ if (pci_dev->no_shutdown) -+ return; -+ - pm_runtime_resume(dev); - - if (drv && drv->shutdown) -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index d797df6e5f3e..c674ee496a0b 100644 ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -6250,3 +6250,39 @@ static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev) - pdev->d3cold_delay = 1000; - } - DECLARE_PCI_FIXUP_FINAL(0x5555, 0x0004, pci_fixup_d3cold_delay_1sec); -+ -+static const struct dmi_system_id no_shutdown_dmi_table[] = { -+ /* -+ * Systems on which some devices should not be touched during shutdown. -+ */ -+ { -+ .ident = "Microsoft Surface Pro 9", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), -+ }, -+ }, -+ { -+ .ident = "Microsoft Surface Laptop 5", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), -+ }, -+ }, -+ {} -+}; -+ -+static void quirk_no_shutdown(struct pci_dev *dev) -+{ -+ if (!dmi_check_system(no_shutdown_dmi_table)) -+ return; -+ -+ dev->no_shutdown = 1; -+ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", -+ dev->vendor, dev->device); -+} -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU -diff --git a/include/linux/pci.h b/include/linux/pci.h -index 7ab0d13672da..8d8d9225e0db 100644 ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -465,6 +465,7 @@ struct pci_dev { - unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ - unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ - unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ -+ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; /* pci_enable_device has been called */ - --- -2.44.0 - diff --git a/patches/6.8/0011-surface-gpe.patch b/patches/6.8/0011-surface-gpe.patch deleted file mode 100644 index 871f0b0071..0000000000 --- a/patches/6.8/0011-surface-gpe.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 36cf5399fd0f16f10f97c21131d29ebda13607f5 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 12 Mar 2023 01:41:57 +0100 -Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 - -Add the lid GPE used by the Surface Pro 9. - -Signed-off-by: Maximilian Luz -Patchset: surface-gpe ---- - drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index 62fd4004db31..103fc4468262 100644 ---- a/drivers/platform/surface/surface_gpe.c -+++ b/drivers/platform/surface/surface_gpe.c -@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { - {}, - }; - -+static const struct property_entry lid_device_props_l52[] = { -+ PROPERTY_ENTRY_U32("gpe", 0x52), -+ {}, -+}; -+ - static const struct property_entry lid_device_props_l57[] = { - PROPERTY_ENTRY_U32("gpe", 0x57), - {}, -@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { - }, - .driver_data = (void *)lid_device_props_l4B, - }, -+ { -+ /* -+ * We match for SKU here due to product name clash with the ARM -+ * version. -+ */ -+ .ident = "Surface Pro 9", -+ .matches = { -+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), -+ }, -+ .driver_data = (void *)lid_device_props_l52, -+ }, - { - .ident = "Surface Book 1", - .matches = { --- -2.44.0 - diff --git a/patches/6.8/0012-cameras.patch b/patches/6.8/0012-cameras.patch deleted file mode 100644 index 9958a34167..0000000000 --- a/patches/6.8/0012-cameras.patch +++ /dev/null @@ -1,852 +0,0 @@ -From 526bea529e4befa282fcfd01bbadbed7325faf01 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sun, 10 Oct 2021 20:56:57 +0200 -Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an - INT3472 device - -The clk and regulator frameworks expect clk/regulator consumer-devices -to have info about the consumed clks/regulators described in the device's -fw_node. - -To work around cases where this info is not present in the firmware tables, -which is often the case on x86/ACPI devices, both frameworks allow the -provider-driver to attach info about consumers to the clks/regulators -when registering these. - -This causes problems with the probe ordering wrt drivers for consumers -of these clks/regulators. Since the lookups are only registered when the -provider-driver binds, trying to get these clks/regulators before then -results in a -ENOENT error for clks and a dummy regulator for regulators. - -One case where we hit this issue is camera sensors such as e.g. the OV8865 -sensor found on the Microsoft Surface Go. The sensor uses clks, regulators -and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 -ACPI device. There is special platform code handling this and setting -platform_data with the necessary consumer info on the MFD cells -instantiated for the PMIC under: drivers/platform/x86/intel/int3472. - -For this to work properly the ov8865 driver must not bind to the I2C-client -for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and -clk MFD cells have all been fully setup. - -The OV8865 on the Microsoft Surface Go is just one example, all X86 -devices using the Intel IPU3 camera block found on recent Intel SoCs -have similar issues where there is an INT3472 HID ACPI-device, which -describes the clks and regulators, and the driver for this INT3472 device -must be fully initialized before the sensor driver (any sensor driver) -binds for things to work properly. - -On these devices the ACPI nodes describing the sensors all have a _DEP -dependency on the matching INT3472 ACPI device (there is one per sensor). - -This allows solving the probe-ordering problem by delaying the enumeration -(instantiation of the I2C-client in the ov8865 example) of ACPI-devices -which have a _DEP dependency on an INT3472 device. - -The new acpi_dev_ready_for_enumeration() helper used for this is also -exported because for devices, which have the enumeration_by_parent flag -set, the parent-driver will do its own scan of child ACPI devices and -it will try to enumerate those during its probe(). Code doing this such -as e.g. the i2c-core-acpi.c code must call this new helper to ensure -that it too delays the enumeration until all the _DEP dependencies are -met on devices which have the new honor_deps flag set. - -Signed-off-by: Hans de Goede -Patchset: cameras ---- - drivers/acpi/scan.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index e6ed1ba91e5c..b367890b7438 100644 ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -2138,6 +2138,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, - - static void acpi_default_enumeration(struct acpi_device *device) - { -+ if (!acpi_dev_ready_for_enumeration(device)) -+ return; -+ - /* - * Do not enumerate devices with enumeration_by_parent flag set as - * they will be enumerated by their respective parents. --- -2.44.0 - -From d41ef92974135b1c22c2f46cbaba926701e0d4af Mon Sep 17 00:00:00 2001 -From: zouxiaoh -Date: Fri, 25 Jun 2021 08:52:59 +0800 -Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs - -Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, -The IPU driver allocates its own page table that is not mapped -via the DMA, and thus the Intel IOMMU driver blocks access giving -this error: DMAR: DRHD: handling fault status reg 3 DMAR: -[DMA Read] Request device [00:05.0] PASID ffffffff -fault addr 76406000 [fault reason 06] PTE Read access is not set -As IPU is not an external facing device which is not risky, so use -IOMMU passthrough mode for Intel IPUs. - -Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b -Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 -Tracked-On: #JIITL8-411 -Signed-off-by: Bingbu Cao -Signed-off-by: zouxiaoh -Signed-off-by: Xu Chongyang -Patchset: cameras ---- - drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 6c01b1aebf27..ceed043464b1 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -45,6 +45,13 @@ - ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ - ) - -+#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ -+ ((pdev)->device == 0x9a19 || \ -+ (pdev)->device == 0x9a39 || \ -+ (pdev)->device == 0x4e19 || \ -+ (pdev)->device == 0x465d || \ -+ (pdev)->device == 0x1919)) -+ - #define IOAPIC_RANGE_START (0xfee00000) - #define IOAPIC_RANGE_END (0xfeefffff) - #define IOVA_START_ADDR (0x1000) -@@ -154,12 +161,14 @@ EXPORT_SYMBOL_GPL(intel_iommu_enabled); - - static int dmar_map_gfx = 1; - static int dmar_map_ipts = 1; -+static int dmar_map_ipu = 1; - static int intel_iommu_superpage = 1; - static int iommu_identity_mapping; - static int iommu_skip_te_disable; - - #define IDENTMAP_GFX 2 - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPU 8 - #define IDENTMAP_IPTS 16 - - const struct iommu_ops intel_iommu_ops; -@@ -2420,6 +2429,9 @@ static int device_def_domain_type(struct device *dev) - if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev)) - return IOMMU_DOMAIN_IDENTITY; - -+ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; -+ - if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) - return IOMMU_DOMAIN_IDENTITY; - } -@@ -2729,6 +2741,9 @@ static int __init init_dmars(void) - if (!dmar_map_gfx) - iommu_identity_mapping |= IDENTMAP_GFX; - -+ if (!dmar_map_ipu) -+ iommu_identity_mapping |= IDENTMAP_IPU; -+ - if (!dmar_map_ipts) - iommu_identity_mapping |= IDENTMAP_IPTS; - -@@ -4909,6 +4924,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - dmar_map_gfx = 0; - } - -+static void quirk_iommu_ipu(struct pci_dev *dev) -+{ -+ if (!IS_INTEL_IPU(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; -+ -+ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); -+ dmar_map_ipu = 0; -+} -+ - static void quirk_iommu_ipts(struct pci_dev *dev) - { - if (!IS_IPTS(dev)) -@@ -4956,6 +4983,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); - -+/* disable IPU dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); -+ - /* disable IPTS dmar support */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); --- -2.44.0 - -From 214600c4c0c3039ba0d0a5e522a2eb162da3857b Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Sun, 10 Oct 2021 20:57:02 +0200 -Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain - -The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic -can be forwarded to a device connected to the PMIC as though it were -connected directly to the system bus. Enable this mode when the chip -is initialised. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 1e107fd49f82..e3e1696e7f0e 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) - return ret; - } - -+ /* Enable I2C daisy chain */ -+ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); -+ if (ret) { -+ dev_err(dev, "Failed to enable i2c daisy chain\n"); -+ return ret; -+ } -+ - dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); - - return 0; --- -2.44.0 - -From f5c4f5e1de99e04416ddffca65246a7769a202e3 Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Thu, 2 Mar 2023 12:59:39 +0000 -Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E - -ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The -driver for this sensor expects a single pin named "enable", but on -some Microsoft Surface platforms the sensor is assigned a single -GPIO who's type flag is INT3472_GPIO_TYPE_RESET. - -Remap the GPIO pin's function from "reset" to "enable". This is done -outside of the existing remap table since it is a more widespread -discrepancy than that method is designed for. Additionally swap the -polarity of the pin to match the driver's expectation. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/discrete.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 07b302e09340..1d3097bc7e48 100644 ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - const char *func, u32 polarity) - { - int ret; -+ const struct acpi_device_id ov7251_ids[] = { -+ { "INT347E" }, -+ }; - - if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { - dev_warn(int3472->dev, "Too many GPIOs mapped\n"); - return -EINVAL; - } - -+ /* -+ * In addition to the function remap table we need to bulk remap the -+ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that -+ * expects its only GPIO pin to be called "enable" (and to have the -+ * opposite polarity). -+ */ -+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { -+ func = "enable"; -+ polarity = GPIO_ACTIVE_HIGH; -+ } -+ - ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, func, polarity); - if (ret) --- -2.44.0 - -From 216df183e0ad29051b42fcb856d0818a6094f16d Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Tue, 21 Mar 2023 13:45:26 +0000 -Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 - -Update the control ID for the gain control in the ov7251 driver to -V4L2_CID_ANALOGUE_GAIN. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/media/i2c/ov7251.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf..9c1292ca8552 100644 ---- a/drivers/media/i2c/ov7251.c -+++ b/drivers/media/i2c/ov7251.c -@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) - case V4L2_CID_EXPOSURE: - ret = ov7251_set_exposure(ov7251, ctrl->val); - break; -- case V4L2_CID_GAIN: -+ case V4L2_CID_ANALOGUE_GAIN: - ret = ov7251_set_gain(ov7251, ctrl->val); - break; - case V4L2_CID_TEST_PATTERN: -@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) - ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, - V4L2_CID_EXPOSURE, 1, 32, 1, 32); - ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, -- V4L2_CID_GAIN, 16, 1023, 1, 16); -+ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); - v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, - V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(ov7251_test_pattern_menu) - 1, --- -2.44.0 - -From 0573bb8c22ed0f0476a2ca6c5df2a7f09c6a1b66 Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Wed, 22 Mar 2023 11:01:42 +0000 -Subject: [PATCH] media: v4l2-core: Acquire privacy led in - v4l2_async_register_subdev() - -The current call to v4l2_subdev_get_privacy_led() is contained in -v4l2_async_register_subdev_sensor(), but that function isn't used by -all the sensor drivers. Move the acquisition of the privacy led to -v4l2_async_register_subdev() instead. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/media/v4l2-core/v4l2-async.c | 4 ++++ - drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index 3ec323bd528b..b55570a0142c 100644 ---- a/drivers/media/v4l2-core/v4l2-async.c -+++ b/drivers/media/v4l2-core/v4l2-async.c -@@ -796,6 +796,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) - - INIT_LIST_HEAD(&sd->asc_list); - -+ ret = v4l2_subdev_get_privacy_led(sd); -+ if (ret < 0) -+ return ret; -+ - /* - * No reference taken. The reference is held by the device (struct - * v4l2_subdev.dev), and async sub-device does not exist independently -diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index 89c7192148df..44eca113e772 100644 ---- a/drivers/media/v4l2-core/v4l2-fwnode.c -+++ b/drivers/media/v4l2-core/v4l2-fwnode.c -@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) - - v4l2_async_subdev_nf_init(notifier, sd); - -- ret = v4l2_subdev_get_privacy_led(sd); -- if (ret < 0) -- goto out_cleanup; -- - ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); - if (ret < 0) - goto out_cleanup; --- -2.44.0 - -From 84d70102a7892f720a11a0b3d313f3932c859798 Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:16 +0800 -Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED - -Add MFD cell for tps68470-led. - -Reviewed-by: Daniel Scally -Signed-off-by: Kate Hsuan -Reviewed-by: Hans de Goede -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index e3e1696e7f0e..423dc555093f 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -17,7 +17,7 @@ - #define DESIGNED_FOR_CHROMEOS 1 - #define DESIGNED_FOR_WINDOWS 2 - --#define TPS68470_WIN_MFD_CELL_COUNT 3 -+#define TPS68470_WIN_MFD_CELL_COUNT 4 - - static const struct mfd_cell tps68470_cros[] = { - { .name = "tps68470-gpio" }, -@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) - cells[1].name = "tps68470-regulator"; - cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; - cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); -- cells[2].name = "tps68470-gpio"; -+ cells[2].name = "tps68470-led"; -+ cells[3].name = "tps68470-gpio"; - - for (i = 0; i < board_data->n_gpiod_lookups; i++) - gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); --- -2.44.0 - -From 183f7e4da9cacc2a0f9cb3549adad9a3c95f1b94 Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:17 +0800 -Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB - -Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB -(TPS68470_ILEDCTL_ENB), and current control mask for LEDB -(TPS68470_ILEDCTL_CTRLB) - -Reviewed-by: Daniel Scally -Reviewed-by: Hans de Goede -Signed-off-by: Kate Hsuan -Patchset: cameras ---- - include/linux/mfd/tps68470.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 ---- a/include/linux/mfd/tps68470.h -+++ b/include/linux/mfd/tps68470.h -@@ -34,6 +34,7 @@ - #define TPS68470_REG_SGPO 0x22 - #define TPS68470_REG_GPDI 0x26 - #define TPS68470_REG_GPDO 0x27 -+#define TPS68470_REG_ILEDCTL 0x28 - #define TPS68470_REG_VCMVAL 0x3C - #define TPS68470_REG_VAUX1VAL 0x3D - #define TPS68470_REG_VAUX2VAL 0x3E -@@ -94,4 +95,8 @@ - #define TPS68470_GPIO_MODE_OUT_CMOS 2 - #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 - -+#define TPS68470_ILEDCTL_ENA BIT(2) -+#define TPS68470_ILEDCTL_ENB BIT(6) -+#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) -+ - #endif /* __LINUX_MFD_TPS68470_H */ --- -2.44.0 - -From 0f3811853f436eed853d7d226eb811f65137d03a Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:18 +0800 -Subject: [PATCH] leds: tps68470: Add LED control for tps68470 - -There are two LED controllers, LEDA indicator LED and LEDB flash LED for -tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, -tps68470 provides four levels of power status for LEDB. If the -properties called "ti,ledb-current" can be found, the current will be -set according to the property values. These two LEDs can be controlled -through the LED class of sysfs (tps68470-leda and tps68470-ledb). - -Signed-off-by: Kate Hsuan -Reviewed-by: Hans de Goede -Patchset: cameras ---- - drivers/leds/Kconfig | 12 +++ - drivers/leds/Makefile | 1 + - drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ - 3 files changed, 198 insertions(+) - create mode 100644 drivers/leds/leds-tps68470.c - -diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index d721b254e1e4..1717f94d1491 100644 ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -899,6 +899,18 @@ config LEDS_TPS6105X - It is a single boost converter primarily for white LEDs and - audio amplifiers. - -+config LEDS_TPS68470 -+ tristate "LED support for TI TPS68470" -+ depends on LEDS_CLASS -+ depends on INTEL_SKL_INT3472 -+ help -+ This driver supports TPS68470 PMIC with LED chip. -+ It provides two LED controllers, with the ability to drive 2 -+ indicator LEDs and 2 flash LEDs. -+ -+ To compile this driver as a module, choose M and it will be -+ called leds-tps68470 -+ - config LEDS_IP30 - tristate "LED support for SGI Octane machines" - depends on LEDS_CLASS -diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index ce07dc295ff0..0ebf6a9f9f7f 100644 ---- a/drivers/leds/Makefile -+++ b/drivers/leds/Makefile -@@ -86,6 +86,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o - obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o - obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o - obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o -+obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o - obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o - obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o - obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o -diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c -new file mode 100644 -index 000000000000..35aeb5db89c8 ---- /dev/null -+++ b/drivers/leds/leds-tps68470.c -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * LED driver for TPS68470 PMIC -+ * -+ * Copyright (C) 2023 Red Hat -+ * -+ * Authors: -+ * Kate Hsuan -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define lcdev_to_led(led_cdev) \ -+ container_of(led_cdev, struct tps68470_led, lcdev) -+ -+#define led_to_tps68470(led, index) \ -+ container_of(led, struct tps68470_device, leds[index]) -+ -+enum tps68470_led_ids { -+ TPS68470_ILED_A, -+ TPS68470_ILED_B, -+ TPS68470_NUM_LEDS -+}; -+ -+static const char *tps68470_led_names[] = { -+ [TPS68470_ILED_A] = "tps68470-iled_a", -+ [TPS68470_ILED_B] = "tps68470-iled_b", -+}; -+ -+struct tps68470_led { -+ unsigned int led_id; -+ struct led_classdev lcdev; -+}; -+ -+struct tps68470_device { -+ struct device *dev; -+ struct regmap *regmap; -+ struct tps68470_led leds[TPS68470_NUM_LEDS]; -+}; -+ -+enum ctrlb_current { -+ CTRLB_2MA = 0, -+ CTRLB_4MA = 1, -+ CTRLB_8MA = 2, -+ CTRLB_16MA = 3, -+}; -+ -+static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) -+{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, -+ brightness ? TPS68470_ILEDCTL_ENA : 0); -+ case TPS68470_ILED_B: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, -+ brightness ? TPS68470_ILEDCTL_ENB : 0); -+ } -+ return -EINVAL; -+} -+ -+static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) -+{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ int ret = 0; -+ int value = 0; -+ -+ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); -+ if (ret) -+ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); -+ -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ value = value & TPS68470_ILEDCTL_ENA; -+ break; -+ case TPS68470_ILED_B: -+ value = value & TPS68470_ILEDCTL_ENB; -+ break; -+ } -+ -+ return value ? LED_ON : LED_OFF; -+} -+ -+ -+static int tps68470_ledb_current_init(struct platform_device *pdev, -+ struct tps68470_device *tps68470) -+{ -+ int ret = 0; -+ unsigned int curr; -+ -+ /* configure LEDB current if the properties can be got */ -+ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { -+ if (curr > CTRLB_16MA) { -+ dev_err(&pdev->dev, -+ "Invalid LEDB current value: %d\n", -+ curr); -+ return -EINVAL; -+ } -+ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, -+ TPS68470_ILEDCTL_CTRLB, curr); -+ } -+ return ret; -+} -+ -+static int tps68470_leds_probe(struct platform_device *pdev) -+{ -+ int i = 0; -+ int ret = 0; -+ struct tps68470_device *tps68470; -+ struct tps68470_led *led; -+ struct led_classdev *lcdev; -+ -+ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), -+ GFP_KERNEL); -+ if (!tps68470) -+ return -ENOMEM; -+ -+ tps68470->dev = &pdev->dev; -+ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); -+ -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ led = &tps68470->leds[i]; -+ lcdev = &led->lcdev; -+ -+ led->led_id = i; -+ -+ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", -+ tps68470_led_names[i], LED_FUNCTION_INDICATOR); -+ if (!lcdev->name) -+ return -ENOMEM; -+ -+ lcdev->max_brightness = 1; -+ lcdev->brightness = 0; -+ lcdev->brightness_set_blocking = tps68470_brightness_set; -+ lcdev->brightness_get = tps68470_brightness_get; -+ lcdev->dev = &pdev->dev; -+ -+ ret = devm_led_classdev_register(tps68470->dev, lcdev); -+ if (ret) { -+ dev_err_probe(tps68470->dev, ret, -+ "error registering led\n"); -+ goto err_exit; -+ } -+ -+ if (i == TPS68470_ILED_B) { -+ ret = tps68470_ledb_current_init(pdev, tps68470); -+ if (ret) -+ goto err_exit; -+ } -+ } -+ -+err_exit: -+ if (ret) { -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ if (tps68470->leds[i].lcdev.name) -+ devm_led_classdev_unregister(&pdev->dev, -+ &tps68470->leds[i].lcdev); -+ } -+ } -+ -+ return ret; -+} -+static struct platform_driver tps68470_led_driver = { -+ .driver = { -+ .name = "tps68470-led", -+ }, -+ .probe = tps68470_leds_probe, -+}; -+ -+module_platform_driver(tps68470_led_driver); -+ -+MODULE_ALIAS("platform:tps68470-led"); -+MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); -+MODULE_LICENSE("GPL v2"); --- -2.44.0 - -From 87ebc160cb35a068acfaf59847c84656cb52b1b7 Mon Sep 17 00:00:00 2001 -From: Sakari Ailus -Date: Thu, 25 May 2023 14:12:04 +0300 -Subject: [PATCH] media: ipu3-cio2: Further clean up async subdev link creation - -Use v4l2_create_fwnode_links_to_pad() to create links from async -sub-devices to the CSI-2 receiver subdevs. - -Signed-off-by: Sakari Ailus -Reviewed-by: Laurent Pinchart -Signed-off-by: Hans Verkuil -Patchset: cameras ---- - drivers/media/pci/intel/ipu3/ipu3-cio2.c | 22 +++++----------------- - 1 file changed, 5 insertions(+), 17 deletions(-) - -diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c -index ed08bf4178f0..83e29c56fe33 100644 ---- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c -+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -1407,7 +1408,6 @@ static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier, - static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) - { - struct cio2_device *cio2 = to_cio2_device(notifier); -- struct device *dev = &cio2->pci_dev->dev; - struct sensor_async_subdev *s_asd; - struct v4l2_async_connection *asd; - struct cio2_queue *q; -@@ -1417,23 +1417,10 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) - s_asd = to_sensor_asd(asd); - q = &cio2->queue[s_asd->csi2.port]; - -- ret = media_entity_get_fwnode_pad(&q->sensor->entity, -- s_asd->asd.match.fwnode, -- MEDIA_PAD_FL_SOURCE); -- if (ret < 0) { -- dev_err(dev, "no pad for endpoint %pfw (%d)\n", -- s_asd->asd.match.fwnode, ret); -- return ret; -- } -- -- ret = media_create_pad_link(&q->sensor->entity, ret, -- &q->subdev.entity, CIO2_PAD_SINK, -- 0); -- if (ret) { -- dev_err(dev, "failed to create link for %s (endpoint %pfw, error %d)\n", -- q->sensor->name, s_asd->asd.match.fwnode, ret); -+ ret = v4l2_create_fwnode_links_to_pad(asd->sd, -+ &q->subdev_pads[CIO2_PAD_SINK], 0); -+ if (ret) - return ret; -- } - } - - return v4l2_device_register_subdev_nodes(&cio2->v4l2_dev); -@@ -1572,6 +1559,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) - v4l2_subdev_init(subdev, &cio2_subdev_ops); - subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; - subdev->owner = THIS_MODULE; -+ subdev->dev = dev; - snprintf(subdev->name, sizeof(subdev->name), - CIO2_ENTITY_NAME " %td", q - cio2->queue); - subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; --- -2.44.0 - -From c5d6c95fd5cefbd4ba9779fc965bce0a36bdbe5e Mon Sep 17 00:00:00 2001 -From: mojyack -Date: Sat, 3 Feb 2024 12:59:53 +0900 -Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on - stream stop - -Adapt to 009905e "media: v4l2-subdev: Document and enforce .s_stream() requirements" - -Patchset: cameras ---- - drivers/staging/media/ipu3/ipu3-v4l2.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c -index 3df58eb3e882..81aff2d5d898 100644 ---- a/drivers/staging/media/ipu3/ipu3-v4l2.c -+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c -@@ -538,18 +538,18 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq) - - WARN_ON(!node->enabled); - -- pipe = node->pipe; -- dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); -- imgu_pipe = &imgu->imgu_pipe[pipe]; -- r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); -- if (r) -- dev_err(&imgu->pci_dev->dev, -- "failed to stop subdev streaming\n"); -- - mutex_lock(&imgu->streaming_lock); - /* Was this the first node with streaming disabled? */ - if (imgu->streaming && imgu_all_nodes_streaming(imgu, node)) { - /* Yes, really stop streaming now */ -+ pipe = node->pipe; -+ dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); -+ imgu_pipe = &imgu->imgu_pipe[pipe]; -+ r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); -+ if (r) -+ dev_err(&imgu->pci_dev->dev, -+ "failed to stop subdev streaming\n"); -+ - dev_dbg(dev, "IMGU streaming is ready to stop"); - r = imgu_s_stream(imgu, false); - if (!r) --- -2.44.0 - -From 65421dfc17e3559d45345ea2aa48b44268653496 Mon Sep 17 00:00:00 2001 -From: mojyack -Date: Tue, 26 Mar 2024 05:55:44 +0900 -Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 - -On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". -The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. -So just add some delay. -There is no exact reason for this 10000us, but 100us failed. ---- - drivers/media/i2c/dw9719.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..0094cfda57ea 100644 ---- a/drivers/media/i2c/dw9719.c -+++ b/drivers/media/i2c/dw9719.c -@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) - if (ret) - return ret; - -+ /* Wait for device to be acknowledged */ -+ fsleep(10000); -+ - /* Jiggle SCL pin to wake up device */ - cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); - --- -2.44.0 - diff --git a/patches/6.8/0013-amd-gpio.patch b/patches/6.8/0013-amd-gpio.patch deleted file mode 100644 index 9b12bd1a75..0000000000 --- a/patches/6.8/0013-amd-gpio.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 302d8dc26283bc10ba22bc549c41292d00125e60 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Sat, 29 May 2021 17:47:38 +1000 -Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 - override - -This patch is the work of Thomas Gleixner and is -copied from: -https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ - -This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin -setup that is missing in the laptops ACPI table. - -This patch was used for validation of the issue, and is not a proper -fix, but is probably a better temporary hack than continuing to probe -the Legacy PIC and run with the PIC in an unknown state. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 85a3ce2a3666..2c0e04a3a697 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -1251,6 +1252,17 @@ static void __init mp_config_acpi_legacy_irqs(void) - } - } - -+static const struct dmi_system_id surface_quirk[] __initconst = { -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") -+ }, -+ }, -+ {} -+}; -+ - /* - * Parse IOAPIC related entries in MADT - * returns 0 on success, < 0 on error -@@ -1306,6 +1318,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) - acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, - acpi_gbl_FADT.sci_interrupt); - -+ if (dmi_check_system(surface_quirk)) { -+ pr_warn("Surface hack: Override irq 7\n"); -+ mp_override_legacy_irq(7, 3, 3, 7); -+ } -+ - /* Fill in identity legacy mappings where no override */ - mp_config_acpi_legacy_irqs(); - --- -2.44.0 - -From d2a793e4fd47cd1cba2847915e7078671d9e9ea5 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Thu, 3 Jun 2021 14:04:26 +0200 -Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override - quirk - -The 13" version of the Surface Laptop 4 has the same problem as the 15" -version, but uses a different SKU. Add that SKU to the quirk as well. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 2c0e04a3a697..b0e1dab3d2ec 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -1254,12 +1254,19 @@ static void __init mp_config_acpi_legacy_irqs(void) - - static const struct dmi_system_id surface_quirk[] __initconst = { - { -- .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") - }, - }, -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") -+ }, -+ }, - {} - }; - --- -2.44.0 - diff --git a/patches/6.8/0014-rtc.patch b/patches/6.8/0014-rtc.patch deleted file mode 100644 index 21ba633f8f..0000000000 --- a/patches/6.8/0014-rtc.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 34ad5b493b00c944ed68d2436cad96785fe37a33 Mon Sep 17 00:00:00 2001 -From: "Bart Groeneveld | GPX Solutions B.V" -Date: Mon, 5 Dec 2022 16:08:46 +0100 -Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms - -The specification [1] allows so-called HW-reduced platforms, -which do not implement everything, especially the wakeup related stuff. - -In that case, it is still usable as a RTC. This is helpful for [2] -and [3], which is about a device with no other working RTC, -but it does have an HW-reduced TAD, which can be used as a RTC instead. - -[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device -[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 -[3]: https://github.com/linux-surface/linux-surface/issues/415 - -Signed-off-by: Bart Groeneveld | GPX Solutions B.V. -Patchset: rtc ---- - drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ - 1 file changed, 24 insertions(+), 12 deletions(-) - -diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 33c3b16af556..900445d06623 100644 ---- a/drivers/acpi/acpi_tad.c -+++ b/drivers/acpi/acpi_tad.c -@@ -432,6 +432,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RO(caps); - -+static struct attribute *acpi_tad_attrs[] = { -+ &dev_attr_caps.attr, -+ NULL, -+}; -+static const struct attribute_group acpi_tad_attr_group = { -+ .attrs = acpi_tad_attrs, -+}; -+ - static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) - { -@@ -480,15 +488,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RW(ac_status); - --static struct attribute *acpi_tad_attrs[] = { -- &dev_attr_caps.attr, -+static struct attribute *acpi_tad_ac_attrs[] = { - &dev_attr_ac_alarm.attr, - &dev_attr_ac_policy.attr, - &dev_attr_ac_status.attr, - NULL, - }; --static const struct attribute_group acpi_tad_attr_group = { -- .attrs = acpi_tad_attrs, -+static const struct attribute_group acpi_tad_ac_attr_group = { -+ .attrs = acpi_tad_ac_attrs, - }; - - static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, -@@ -564,13 +571,18 @@ static int acpi_tad_remove(struct platform_device *pdev) - - pm_runtime_get_sync(dev); - -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) -+ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ - if (dd->capabilities & ACPI_TAD_DC_WAKE) - sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); - - sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); - -- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) { -+ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -+ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ } - if (dd->capabilities & ACPI_TAD_DC_WAKE) { - acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); - acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); -@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) - goto remove_handler; - } - -- if (!acpi_has_method(handle, "_PRW")) { -- dev_info(dev, "Missing _PRW\n"); -- ret = -ENODEV; -- goto remove_handler; -- } -- - dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); - if (!dd) { - ret = -ENOMEM; -@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) - if (ret) - goto fail; - -+ if (caps & ACPI_TAD_AC_WAKE) { -+ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ if (ret) -+ goto fail; -+ } -+ - if (caps & ACPI_TAD_DC_WAKE) { - ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); - if (ret) --- -2.44.0 - From 5e25cad4d0d621890b670a8f13bdcd0e18327b69 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Aug 2024 16:32:27 +0200 Subject: [PATCH 041/236] Update v6.9 patches Changes: - Update ITHC - Enable support for SL6 and SP10 - Add Fixes for SP8 - Based on https://github.com/quo/ithc-linux/commit/34539af4726d970f9765363bb78b5fd920611a0b Links: - kernel: https://github.com/linux-surface/kernel/commit/22cdd5415bd4420622e1a3439f2975ffde071801 --- patches/6.9/0001-secureboot.patch | 6 +- patches/6.9/0002-surface3-oemb.patch | 10 +- patches/6.9/0003-mwifiex.patch | 26 +- patches/6.9/0004-ath10k.patch | 6 +- patches/6.9/0005-ipts.patch | 84 ++-- patches/6.9/0006-ithc.patch | 405 ++++++++++++++++++-- patches/6.9/0007-surface-sam.patch | 84 ++-- patches/6.9/0008-surface-sam-over-hid.patch | 16 +- patches/6.9/0009-surface-button.patch | 12 +- patches/6.9/0010-surface-typecover.patch | 18 +- patches/6.9/0011-surface-shutdown.patch | 10 +- patches/6.9/0012-surface-gpe.patch | 6 +- patches/6.9/0013-cameras.patch | 72 ++-- patches/6.9/0014-amd-gpio.patch | 12 +- patches/6.9/0015-rtc.patch | 6 +- 15 files changed, 556 insertions(+), 217 deletions(-) diff --git a/patches/6.9/0001-secureboot.patch b/patches/6.9/0001-secureboot.patch index 06f45fc2ee..186d419ce1 100644 --- a/patches/6.9/0001-secureboot.patch +++ b/patches/6.9/0001-secureboot.patch @@ -1,4 +1,4 @@ -From a4b96f72850f2e7259e12c3a4a9d59131078a49e Mon Sep 17 00:00:00 2001 +From 0a65c8b311295b6fda9386f397a4adc1e3dc28b5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -17,7 +17,7 @@ Patchset: secureboot 1 file changed, 4 insertions(+) diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index b5c79f43359bc..a1bbedd989e42 100644 +index b5c79f43359b..a1bbedd989e4 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -111,7 +111,11 @@ extra_header_fields: @@ -33,5 +33,5 @@ index b5c79f43359bc..a1bbedd989e42 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0002-surface3-oemb.patch b/patches/6.9/0002-surface3-oemb.patch index 6f65d62542..de56b9f6bf 100644 --- a/patches/6.9/0002-surface3-oemb.patch +++ b/patches/6.9/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From c70635debfb516e9fd4e6e1a627a184ef1a7ebf9 Mon Sep 17 00:00:00 2001 +From 3878b34a7bc634d6293876adb4f66f7ba332eb4a Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -40,7 +40,7 @@ Patchset: surface3-oemb 3 files changed, 24 insertions(+) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index c15ed7a12784a..1ec8edb5aafaf 100644 +index c15ed7a12784..1ec8edb5aafa 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { @@ -58,7 +58,7 @@ index c15ed7a12784a..1ec8edb5aafaf 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index d0d24a53df746..43e06166a5d95 100644 +index d0d24a53df74..43e06166a5d9 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3777,6 +3777,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -78,7 +78,7 @@ index d0d24a53df746..43e06166a5d95 100644 /* * Match for the GPDwin which unfortunately uses somewhat diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index 5e2ec60e2954b..207868c699f29 100644 +index 5e2ec60e2954..207868c699f2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { @@ -97,5 +97,5 @@ index 5e2ec60e2954b..207868c699f29 100644 }; -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0003-mwifiex.patch b/patches/6.9/0003-mwifiex.patch index 290e0bc02f..bdc6f4ea86 100644 --- a/patches/6.9/0003-mwifiex.patch +++ b/patches/6.9/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 7a613d68d8ec81985333f0ccbd3c7e2515a8396c Mon Sep 17 00:00:00 2001 +From 20f0445b1c1b466002feed9461a2244c4426ea21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -32,7 +32,7 @@ Patchset: mwifiex 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 5f997becdbaa2..9a9929424513a 100644 +index 5f997becdbaa..9a9929424513 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) @@ -58,7 +58,7 @@ index 5f997becdbaa2..9a9929424513a 100644 mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd7..f46b06f8d6435 100644 +index dd6d21f1dbfd..f46b06f8d643 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -151,7 +151,7 @@ index dd6d21f1dbfd7..f46b06f8d6435 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5bf..5d30ae39d65ec 100644 +index d6ff964aec5b..5d30ae39d65e 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -4,6 +4,7 @@ @@ -163,9 +163,9 @@ index d6ff964aec5bf..5d30ae39d65ec 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.45.1 +2.45.2 -From 72063300ceaac5353d979ab3fb1c90431d49973d Mon Sep 17 00:00:00 2001 +From a6da6d0ae56bfcb0a6cbb29ffa5084f68d33ff80 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -187,7 +187,7 @@ Patchset: mwifiex 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 9a9929424513a..2273e30297766 100644 +index 9a9929424513..2273e3029776 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, @@ -212,7 +212,7 @@ index 9a9929424513a..2273e30297766 100644 } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d6435..99b024ecbadea 100644 +index f46b06f8d643..99b024ecbade 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -306,7 +306,7 @@ index f46b06f8d6435..99b024ecbadea 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65ec..c14eb56eb9118 100644 +index 5d30ae39d65e..c14eb56eb911 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -5,6 +5,7 @@ @@ -318,9 +318,9 @@ index 5d30ae39d65ec..c14eb56eb9118 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.45.1 +2.45.2 -From ba70b3a57603beac9f007e173a7189ad12056a16 Mon Sep 17 00:00:00 2001 +From 44f49d2976d1b066787084164f231a6752dc056c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index fb716849b60f3..1e7b3798108f7 100644 +index fb716849b60f..1e7b3798108f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -396,5 +396,5 @@ index fb716849b60f3..1e7b3798108f7 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0004-ath10k.patch b/patches/6.9/0004-ath10k.patch index 93f6a59d06..9e000bdfaa 100644 --- a/patches/6.9/0004-ath10k.patch +++ b/patches/6.9/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 3d6d8efe56a7b9ad8cea6616c918f5c057ec97c6 Mon Sep 17 00:00:00 2001 +From f5c625e43ac2d2dcd37ed08391e3a6e40437cc81 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 58 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index fa5e2e6518313..8921b0ebf36b7 100644 +index fa5e2e651831..8921b0ebf36b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -39,6 +39,9 @@ static bool fw_diag_log; @@ -117,5 +117,5 @@ index fa5e2e6518313..8921b0ebf36b7 100644 ret = firmware_request_nowarn(&fw, filename, ar->dev); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0005-ipts.patch b/patches/6.9/0005-ipts.patch index e967801eea..e47882043f 100644 --- a/patches/6.9/0005-ipts.patch +++ b/patches/6.9/0005-ipts.patch @@ -1,4 +1,4 @@ -From c2d6692b776f0d082e204f153ee9cca409e6aa1d Mon Sep 17 00:00:00 2001 +From 22e330a89ef3a3b8765bffcc67ad1426c715ff46 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index c3a6657dcd4a2..82eef2f4eb0a8 100644 +index c3a6657dcd4a..82eef2f4eb0a 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index c3a6657dcd4a2..82eef2f4eb0a8 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 6589635f8ba32..a1df48a434e2f 100644 +index 6589635f8ba3..a1df48a434e2 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index 6589635f8ba32..a1df48a434e2f 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.45.1 +2.45.2 -From 070ffec42eb5b8e6c0403bbcaa86a6bd19323dea Mon Sep 17 00:00:00 2001 +From 11229997041587d1c0613fc274e87b442c6596d9 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index e4a03588a8a0f..61bc54299a591 100644 +index e4a03588a8a0..61bc54299a59 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -142,9 +142,9 @@ index e4a03588a8a0f..61bc54299a591 100644 { if (risky_device(dev)) -- -2.45.1 +2.45.2 -From 2e10f861a1556ad45bf1e4a7d5c81806653cdeb7 Mon Sep 17 00:00:00 2001 +From 2bd70f61f21bd369fcb90399530b9d2e63ad91b6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,7 +211,7 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 4c682c6507040..a263e49b2ae29 100644 +index 4c682c650704..a263e49b2ae2 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1351,4 +1351,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" @@ -222,7 +222,7 @@ index 4c682c6507040..a263e49b2ae29 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 082a728eac600..f4bad1b8d813f 100644 +index 082a728eac60..f4bad1b8d813 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -170,3 +170,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ @@ -233,7 +233,7 @@ index 082a728eac600..f4bad1b8d813f 100644 +obj-$(CONFIG_HID_IPTS) += ipts/ diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 0000000000000..297401bd388dd +index 000000000000..297401bd388d --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -253,7 +253,7 @@ index 0000000000000..297401bd388dd + module will be called ipts. diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile new file mode 100644 -index 0000000000000..883896f68e6ad +index 000000000000..883896f68e6a --- /dev/null +++ b/drivers/hid/ipts/Makefile @@ -0,0 +1,16 @@ @@ -275,7 +275,7 @@ index 0000000000000..883896f68e6ad +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 0000000000000..63a4934bbc5fa +index 000000000000..63a4934bbc5f --- /dev/null +++ b/drivers/hid/ipts/cmd.c @@ -0,0 +1,61 @@ @@ -342,7 +342,7 @@ index 0000000000000..63a4934bbc5fa +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 0000000000000..2b4079075b642 +index 000000000000..2b4079075b64 --- /dev/null +++ b/drivers/hid/ipts/cmd.h @@ -0,0 +1,60 @@ @@ -408,7 +408,7 @@ index 0000000000000..2b4079075b642 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 0000000000000..ba33259f1f7c5 +index 000000000000..ba33259f1f7c --- /dev/null +++ b/drivers/hid/ipts/context.h @@ -0,0 +1,52 @@ @@ -466,7 +466,7 @@ index 0000000000000..ba33259f1f7c5 +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 0000000000000..5360842d260ba +index 000000000000..5360842d260b --- /dev/null +++ b/drivers/hid/ipts/control.c @@ -0,0 +1,486 @@ @@ -958,7 +958,7 @@ index 0000000000000..5360842d260ba +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 0000000000000..26629c5144edb +index 000000000000..26629c5144ed --- /dev/null +++ b/drivers/hid/ipts/control.h @@ -0,0 +1,126 @@ @@ -1090,7 +1090,7 @@ index 0000000000000..26629c5144edb +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 0000000000000..307438c7c80cd +index 000000000000..307438c7c80c --- /dev/null +++ b/drivers/hid/ipts/desc.h @@ -0,0 +1,80 @@ @@ -1176,7 +1176,7 @@ index 0000000000000..307438c7c80cd +#endif /* IPTS_DESC_H */ diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 0000000000000..ecbb3a8bdaf60 +index 000000000000..ecbb3a8bdaf6 --- /dev/null +++ b/drivers/hid/ipts/eds1.c @@ -0,0 +1,103 @@ @@ -1285,7 +1285,7 @@ index 0000000000000..ecbb3a8bdaf60 +} diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h new file mode 100644 -index 0000000000000..eeeb6575e3e89 +index 000000000000..eeeb6575e3e8 --- /dev/null +++ b/drivers/hid/ipts/eds1.h @@ -0,0 +1,35 @@ @@ -1326,7 +1326,7 @@ index 0000000000000..eeeb6575e3e89 + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c new file mode 100644 -index 0000000000000..198dc65d78876 +index 000000000000..198dc65d7887 --- /dev/null +++ b/drivers/hid/ipts/eds2.c @@ -0,0 +1,144 @@ @@ -1476,7 +1476,7 @@ index 0000000000000..198dc65d78876 +} diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h new file mode 100644 -index 0000000000000..064e3716907ab +index 000000000000..064e3716907a --- /dev/null +++ b/drivers/hid/ipts/eds2.h @@ -0,0 +1,35 @@ @@ -1517,7 +1517,7 @@ index 0000000000000..064e3716907ab + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c new file mode 100644 -index 0000000000000..e34a1a4f9fa77 +index 000000000000..e34a1a4f9fa7 --- /dev/null +++ b/drivers/hid/ipts/hid.c @@ -0,0 +1,225 @@ @@ -1748,7 +1748,7 @@ index 0000000000000..e34a1a4f9fa77 +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 0000000000000..1ebe77447903a +index 000000000000..1ebe77447903 --- /dev/null +++ b/drivers/hid/ipts/hid.h @@ -0,0 +1,24 @@ @@ -1778,7 +1778,7 @@ index 0000000000000..1ebe77447903a +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 0000000000000..fb5b5c13ee3ea +index 000000000000..fb5b5c13ee3e --- /dev/null +++ b/drivers/hid/ipts/main.c @@ -0,0 +1,126 @@ @@ -1910,7 +1910,7 @@ index 0000000000000..fb5b5c13ee3ea +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 0000000000000..1e0395ceae4a4 +index 000000000000..1e0395ceae4a --- /dev/null +++ b/drivers/hid/ipts/mei.c @@ -0,0 +1,188 @@ @@ -2104,7 +2104,7 @@ index 0000000000000..1e0395ceae4a4 +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 0000000000000..973bade6b0fdd +index 000000000000..973bade6b0fd --- /dev/null +++ b/drivers/hid/ipts/mei.h @@ -0,0 +1,66 @@ @@ -2176,7 +2176,7 @@ index 0000000000000..973bade6b0fdd +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 0000000000000..ef66c3c9db807 +index 000000000000..ef66c3c9db80 --- /dev/null +++ b/drivers/hid/ipts/receiver.c @@ -0,0 +1,250 @@ @@ -2432,7 +2432,7 @@ index 0000000000000..ef66c3c9db807 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 0000000000000..3de7da62d40c1 +index 000000000000..3de7da62d40c --- /dev/null +++ b/drivers/hid/ipts/receiver.h @@ -0,0 +1,16 @@ @@ -2454,7 +2454,7 @@ index 0000000000000..3de7da62d40c1 +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 0000000000000..cc14653b2a9f5 +index 000000000000..cc14653b2a9f --- /dev/null +++ b/drivers/hid/ipts/resources.c @@ -0,0 +1,131 @@ @@ -2591,7 +2591,7 @@ index 0000000000000..cc14653b2a9f5 +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 0000000000000..2068e13285f0e +index 000000000000..2068e13285f0 --- /dev/null +++ b/drivers/hid/ipts/resources.h @@ -0,0 +1,41 @@ @@ -2638,7 +2638,7 @@ index 0000000000000..2068e13285f0e +#endif /* IPTS_RESOURCES_H */ diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h new file mode 100644 -index 0000000000000..e8dd98895a7ee +index 000000000000..e8dd98895a7e --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -2744,7 +2744,7 @@ index 0000000000000..e8dd98895a7ee +#endif /* IPTS_SPEC_DATA_H */ diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h new file mode 100644 -index 0000000000000..41845f9d90257 +index 000000000000..41845f9d9025 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h @@ -0,0 +1,290 @@ @@ -3040,7 +3040,7 @@ index 0000000000000..41845f9d90257 +#endif /* IPTS_SPEC_DEVICE_H */ diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h new file mode 100644 -index 0000000000000..5a58d4a0a610f +index 000000000000..5a58d4a0a610 --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h @@ -0,0 +1,34 @@ @@ -3080,7 +3080,7 @@ index 0000000000000..5a58d4a0a610f +#endif /* IPTS_SPEC_HID_H */ diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c new file mode 100644 -index 0000000000000..355e92bea26f8 +index 000000000000..355e92bea26f --- /dev/null +++ b/drivers/hid/ipts/thread.c @@ -0,0 +1,84 @@ @@ -3170,7 +3170,7 @@ index 0000000000000..355e92bea26f8 +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 0000000000000..1f966b8b32c45 +index 000000000000..1f966b8b32c4 --- /dev/null +++ b/drivers/hid/ipts/thread.h @@ -0,0 +1,59 @@ @@ -3234,9 +3234,9 @@ index 0000000000000..1f966b8b32c45 + +#endif /* IPTS_THREAD_H */ -- -2.45.1 +2.45.2 -From 1930dddc7cf94e188a3cf6e957b9bd8622ba4a6b Mon Sep 17 00:00:00 2001 +From 9548ddae8daf8630884b8dc207df42ea524dc500 Mon Sep 17 00:00:00 2001 From: Jasmin Huber Date: Mon, 15 Apr 2024 10:22:55 +0200 Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile @@ -3251,7 +3251,7 @@ Patchset: ipts 3 files changed, 3 insertions(+) diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c -index ecbb3a8bdaf60..7b9f54388a9f6 100644 +index ecbb3a8bdaf6..7b9f54388a9f 100644 --- a/drivers/hid/ipts/eds1.c +++ b/drivers/hid/ipts/eds1.c @@ -14,6 +14,7 @@ @@ -3263,7 +3263,7 @@ index ecbb3a8bdaf60..7b9f54388a9f6 100644 int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c -index 198dc65d78876..639940794615d 100644 +index 198dc65d7887..639940794615 100644 --- a/drivers/hid/ipts/eds2.c +++ b/drivers/hid/ipts/eds2.c @@ -15,6 +15,7 @@ @@ -3275,7 +3275,7 @@ index 198dc65d78876..639940794615d 100644 int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -index ef66c3c9db807..977724c728c3e 100644 +index ef66c3c9db80..977724c728c3 100644 --- a/drivers/hid/ipts/receiver.c +++ b/drivers/hid/ipts/receiver.c @@ -16,6 +16,7 @@ @@ -3287,5 +3287,5 @@ index ef66c3c9db807..977724c728c3e 100644 #include "spec-device.h" #include "thread.h" -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0006-ithc.patch b/patches/6.9/0006-ithc.patch index 78307cadac..cf2738caaa 100644 --- a/patches/6.9/0006-ithc.patch +++ b/patches/6.9/0006-ithc.patch @@ -1,4 +1,4 @@ -From 28368e616f0710082f3c43e3614650b05a09773c Mon Sep 17 00:00:00 2001 +From 888f8f300f9a547535e251f192759902545208f0 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,7 +10,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 566297bc87ddb..a8cd8f12d5937 100644 +index 566297bc87dd..a8cd8f12d593 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -386,6 +386,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) @@ -37,9 +37,9 @@ index 566297bc87ddb..a8cd8f12d5937 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.45.1 +2.45.2 -From 07b04f9dbdee2152e14ac7777f71ee3a13dd019d Mon Sep 17 00:00:00 2001 +From e5bbe336297f8d6fbaac16f8b091522bb394e30a Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -72,7 +72,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index a263e49b2ae29..03f0f5af289a4 100644 +index a263e49b2ae2..03f0f5af289a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1353,4 +1353,6 @@ source "drivers/hid/surface-hid/Kconfig" @@ -83,7 +83,7 @@ index a263e49b2ae29..03f0f5af289a4 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index f4bad1b8d813f..d32c194400aea 100644 +index f4bad1b8d813..d32c194400ae 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -93,7 +93,7 @@ index f4bad1b8d813f..d32c194400aea 100644 +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 0000000000000..aea83f2ac07b4 +index 000000000000..aea83f2ac07b --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -105,7 +105,7 @@ index 0000000000000..aea83f2ac07b4 + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 0000000000000..ede7130236096 +index 000000000000..ede713023609 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -123,7 +123,7 @@ index 0000000000000..ede7130236096 + module will be called ithc. diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c new file mode 100644 -index 0000000000000..1f1f1e33f2e5a +index 000000000000..1f1f1e33f2e5 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,130 @@ @@ -259,7 +259,7 @@ index 0000000000000..1f1f1e33f2e5a + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 0000000000000..ffb8689b8a780 +index 000000000000..ffb8689b8a78 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,373 @@ @@ -638,7 +638,7 @@ index 0000000000000..ffb8689b8a780 + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 0000000000000..93652e4476bf8 +index 000000000000..93652e4476bf --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,69 @@ @@ -713,7 +713,7 @@ index 0000000000000..93652e4476bf8 + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 0000000000000..87ed4aa70fda0 +index 000000000000..87ed4aa70fda --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,728 @@ @@ -1447,7 +1447,7 @@ index 0000000000000..87ed4aa70fda0 + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 0000000000000..e058721886e37 +index 000000000000..e058721886e3 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,96 @@ @@ -1549,7 +1549,7 @@ index 0000000000000..e058721886e37 + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 0000000000000..d4007d9e2bacc +index 000000000000..d4007d9e2bac --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,189 @@ @@ -1744,7 +1744,7 @@ index 0000000000000..d4007d9e2bacc + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 0000000000000..028e55a4ec53e +index 000000000000..028e55a4ec53 --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,67 @@ @@ -1816,9 +1816,9 @@ index 0000000000000..028e55a4ec53e +void ithc_log_regs(struct ithc *ithc); + -- -2.45.1 +2.45.2 -From 949ce7e16eb91fb96b2495a002364a82ee543f16 Mon Sep 17 00:00:00 2001 +From 299f645a4bc247c2f5adae925f56978870b133f8 Mon Sep 17 00:00:00 2001 From: quo Date: Fri, 19 Apr 2024 22:11:09 +0200 Subject: [PATCH] hid: ithc: Update from quo/ithc-linux @@ -1856,7 +1856,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc-quickspi.h diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild -index aea83f2ac07b4..4937ba1312973 100644 +index aea83f2ac07b..4937ba131297 100644 --- a/drivers/hid/ithc/Kbuild +++ b/drivers/hid/ithc/Kbuild @@ -1,6 +1,6 @@ @@ -1868,7 +1868,7 @@ index aea83f2ac07b4..4937ba1312973 100644 ccflags-y := -std=gnu11 -Wno-declaration-after-statement diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c -index 1f1f1e33f2e5a..2d8c6afe99663 100644 +index 1f1f1e33f2e5..2d8c6afe9966 100644 --- a/drivers/hid/ithc/ithc-debug.c +++ b/drivers/hid/ithc/ithc-debug.c @@ -85,10 +85,11 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si @@ -1935,7 +1935,7 @@ index 1f1f1e33f2e5a..2d8c6afe99663 100644 *dbgm = dbg; diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h new file mode 100644 -index 0000000000000..38c53d916bdb5 +index 000000000000..38c53d916bdb --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.h @@ -0,0 +1,7 @@ @@ -1947,7 +1947,7 @@ index 0000000000000..38c53d916bdb5 +void ithc_log_regs(struct ithc *ithc); + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c -index ffb8689b8a780..bf4eab33062b0 100644 +index ffb8689b8a78..bf4eab33062b 100644 --- a/drivers/hid/ithc/ithc-dma.c +++ b/drivers/hid/ithc/ithc-dma.c @@ -173,10 +173,9 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel) @@ -2128,7 +2128,7 @@ index ffb8689b8a780..bf4eab33062b0 100644 return ret; } diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h -index 93652e4476bf8..1749a5819b3e7 100644 +index 93652e4476bf..1749a5819b3e 100644 --- a/drivers/hid/ithc/ithc-dma.h +++ b/drivers/hid/ithc/ithc-dma.h @@ -11,27 +11,6 @@ struct ithc_phys_region_desc { @@ -2176,7 +2176,7 @@ index 93652e4476bf8..1749a5819b3e7 100644 diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c new file mode 100644 -index 0000000000000..065646ab499ef +index 000000000000..065646ab499e --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.c @@ -0,0 +1,207 @@ @@ -2389,7 +2389,7 @@ index 0000000000000..065646ab499ef + diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h new file mode 100644 -index 0000000000000..599eb912c8c84 +index 000000000000..599eb912c8c8 --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.h @@ -0,0 +1,32 @@ @@ -2427,7 +2427,7 @@ index 0000000000000..599eb912c8c84 + diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c new file mode 100644 -index 0000000000000..5c1da11e3f1d2 +index 000000000000..5c1da11e3f1d --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.c @@ -0,0 +1,252 @@ @@ -2685,7 +2685,7 @@ index 0000000000000..5c1da11e3f1d2 + diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h new file mode 100644 -index 0000000000000..28d6924620722 +index 000000000000..28d692462072 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.h @@ -0,0 +1,8 @@ @@ -2698,7 +2698,7 @@ index 0000000000000..28d6924620722 + size_t maxlen); + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -index 87ed4aa70fda0..2acf02e41d40f 100644 +index 87ed4aa70fda..2acf02e41d40 100644 --- a/drivers/hid/ithc/ithc-main.c +++ b/drivers/hid/ithc/ithc-main.c @@ -5,28 +5,6 @@ @@ -3260,7 +3260,7 @@ index 87ed4aa70fda0..2acf02e41d40f 100644 module_init(ithc_init); diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c new file mode 100644 -index 0000000000000..760e55ead0788 +index 000000000000..760e55ead078 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.c @@ -0,0 +1,578 @@ @@ -3844,7 +3844,7 @@ index 0000000000000..760e55ead0788 + diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h new file mode 100644 -index 0000000000000..74d882f6b2f0a +index 000000000000..74d882f6b2f0 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.h @@ -0,0 +1,39 @@ @@ -3888,7 +3888,7 @@ index 0000000000000..74d882f6b2f0a + size_t maxlen); + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c -index e058721886e37..c0f13506af205 100644 +index e058721886e3..c0f13506af20 100644 --- a/drivers/hid/ithc/ithc-regs.c +++ b/drivers/hid/ithc/ithc-regs.c @@ -22,46 +22,104 @@ void bitsb(__iomem u8 *reg, u8 mask, u8 val) @@ -4004,7 +4004,7 @@ index e058721886e37..c0f13506af205 100644 return -EINVAL; diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h -index d4007d9e2bacc..a9d2364546442 100644 +index d4007d9e2bac..a9d236454644 100644 --- a/drivers/hid/ithc/ithc-regs.h +++ b/drivers/hid/ithc/ithc-regs.h @@ -1,14 +1,34 @@ @@ -4225,7 +4225,7 @@ index d4007d9e2bacc..a9d2364546442 100644 int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h -index 028e55a4ec53e..e90c380444325 100644 +index 028e55a4ec53..e90c38044432 100644 --- a/drivers/hid/ithc/ithc.h +++ b/drivers/hid/ithc/ithc.h @@ -1,20 +1,19 @@ @@ -4336,5 +4336,344 @@ index 028e55a4ec53e..e90c380444325 100644 -void ithc_log_regs(struct ithc *ithc); -- -2.45.1 +2.45.2 + +From 79abe7fc9d3cd1eda0d9904695a98e98eab037aa Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 4 Aug 2024 16:04:53 +0200 +Subject: [PATCH] hid: ithc: Update from quo/ithc-linux + + - Enable support for SL6/SP10 + - Fixes for SP8 + +Based on: https://github.com/quo/ithc-linux/commit/34539af4726d970f9765363bb78b5fd920611a0b + +Signed-off-by: Maximilian Luz +Patchset: ithc +--- + drivers/hid/ithc/ithc-legacy.c | 4 +- + drivers/hid/ithc/ithc-main.c | 91 +++++++++----------------------- + drivers/hid/ithc/ithc-quickspi.c | 53 ++++++++++++++----- + drivers/hid/ithc/ithc-regs.h | 15 +++--- + drivers/hid/ithc/ithc.h | 9 +++- + 5 files changed, 82 insertions(+), 90 deletions(-) + +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +index 5c1da11e3f1d..8883987fb352 100644 +--- a/drivers/hid/ithc/ithc-legacy.c ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -82,8 +82,10 @@ int ithc_legacy_init(struct ithc *ithc) + // Setting the following bit seems to make reading the config more reliable. + bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); + +- // Setting this bit may be necessary on some ADL devices. ++ // Setting this bit may be necessary on ADL devices. + switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: + case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: + case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: + case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +index 2acf02e41d40..ac56c253674b 100644 +--- a/drivers/hid/ithc/ithc-main.c ++++ b/drivers/hid/ithc/ithc-main.c +@@ -6,25 +6,14 @@ MODULE_DESCRIPTION("Intel Touch Host Controller driver"); + MODULE_LICENSE("Dual BSD/GPL"); + + static const struct pci_device_id ithc_pci_tbl[] = { +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_MTL_PORT1) }, +- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_MTL_PORT2) }, +- // XXX So far the THC seems to be the only Intel PCI device with PCI_CLASS_INPUT_PEN, +- // so instead of the device list we could just do: +- // { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .class = PCI_CLASS_INPUT_PEN, .class_mask = ~0, }, ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, + {} + }; + MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); +@@ -52,50 +41,14 @@ static int ithc_idle_ltr_us = -1; + module_param_named(idleltr, ithc_idle_ltr_us, int, 0); + MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); + ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ + static bool ithc_log_regs_enabled = false; + module_param_named(logregs, ithc_log_regs_enabled, bool, 0); + MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); + +-// Sysfs attributes +- +-static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc->have_config) +- return -ENODEV; +- return sprintf(buf, "0x%04x", ithc->vendor_id); +-} +-static DEVICE_ATTR_RO(vendor); +-static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc->have_config) +- return -ENODEV; +- return sprintf(buf, "0x%04x", ithc->product_id); +-} +-static DEVICE_ATTR_RO(product); +-static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct ithc *ithc = dev_get_drvdata(dev); +- if (!ithc || !ithc->have_config) +- return -ENODEV; +- return sprintf(buf, "%u", ithc->product_rev); +-} +-static DEVICE_ATTR_RO(revision); +- +-static const struct attribute_group *ithc_attribute_groups[] = { +- &(const struct attribute_group){ +- .name = DEVNAME, +- .attrs = (struct attribute *[]){ +- &dev_attr_vendor.attr, +- &dev_attr_product.attr, +- &dev_attr_revision.attr, +- NULL +- }, +- }, +- NULL +-}; +- + // Interrupts/polling + + static void ithc_disable_interrupts(struct ithc *ithc) +@@ -124,14 +77,19 @@ static void ithc_clear_interrupts(struct ithc *ithc) + &ithc->regs->dma_tx.status); + } + ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ + static void ithc_process(struct ithc *ithc) + { + ithc_log_regs(ithc); + + // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. +- // It does not appear to automatically go back to idle, so we switch it back here, since +- // the DMA transfer should be complete. +- ithc_set_ltr_idle(ithc); ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); + + bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; + bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; +@@ -231,10 +189,10 @@ static int ithc_init_device(struct ithc *ithc) + // Set Latency Tolerance Reporting config. The device will automatically + // apply these values depending on whether it is active or idle. + // If active value is too high, DMA buffer data can become truncated. +- // By default, we set the active LTR value to 100us, and idle to 100ms. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. + u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 + : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 +- : 100 * 1000; ++ : 50 * 1000; + u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 + : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 + : 100 * 1000 * 1000; +@@ -279,6 +237,7 @@ static void ithc_stop(void *res) + else + ithc_legacy_exit(ithc); + ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); + + // Clear DMA config. + for (unsigned int i = 0; i < 2; i++) { +@@ -343,13 +302,14 @@ static int ithc_start(struct pci_dev *pci) + + // Initialize HID and DMA. + CHECK_RET(ithc_hid_init, ithc); +- CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups); + if (ithc_use_rx0) + CHECK_RET(ithc_dma_rx_init, ithc, 0); + if (ithc_use_rx1) + CHECK_RET(ithc_dma_rx_init, ithc, 1); + CHECK_RET(ithc_dma_tx_init, ithc); + ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ + // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are + // disabled BEFORE the buffers are freed. + CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); +@@ -452,7 +412,6 @@ static struct pci_driver ithc_driver = { + .restore = ithc_restore, + }, + .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, +- //.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway + }; + + static int __init ithc_init(void) +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +index 760e55ead078..e2d1690b8cf8 100644 +--- a/drivers/hid/ithc/ithc-quickspi.c ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -257,6 +257,14 @@ void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cf + spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); + } + ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ + static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) + { + pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); +@@ -279,26 +287,47 @@ static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_con + // SPI addresses and opcodes + if (cfg->has_input_report_header_address) + writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); +- if (cfg->has_input_report_body_address) ++ if (cfg->has_input_report_body_address) { + writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } + if (cfg->has_output_report_body_address) + writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); + +- if (cfg->has_read_opcode) { +- writeb(cfg->read_opcode, &ithc->regs->read_opcode); +- writeb(cfg->read_opcode, &ithc->regs->read_opcode_single); +- writeb(cfg->read_opcode, &ithc->regs->read_opcode_dual); +- writeb(cfg->read_opcode, &ithc->regs->read_opcode_quad); +- } +- if (cfg->has_write_opcode) { +- writeb(cfg->write_opcode, &ithc->regs->write_opcode); +- writeb(cfg->write_opcode, &ithc->regs->write_opcode_single); +- writeb(cfg->write_opcode, &ithc->regs->write_opcode_dual); +- writeb(cfg->write_opcode, &ithc->regs->write_opcode_quad); ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; + } ++ + ithc_log_regs(ithc); + + // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ + bitsl(&ithc->regs->quickspi_config1, + QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | + QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +index a9d236454644..4f541fe533fa 100644 +--- a/drivers/hid/ithc/ithc-regs.h ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -129,15 +129,12 @@ struct ithc_registers { + /* 1008 */ u32 control_bits; + /* 100c */ u32 _unknown_100c; + /* 1010 */ u32 spi_config; +- /* 1014 */ u8 read_opcode; // maybe for header? +- /* 1015 */ u8 read_opcode_quad; +- /* 1016 */ u8 read_opcode_dual; +- /* 1017 */ u8 read_opcode_single; +- /* 1018 */ u8 write_opcode; // not used? +- /* 1019 */ u8 write_opcode_quad; +- /* 101a */ u8 write_opcode_dual; +- /* 101b */ u8 write_opcode_single; +- /* 101c */ u32 _unknown_101c; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; + /* 1020 */ u32 error_control; + /* 1024 */ u32 error_status; // write to clear + /* 1028 */ u32 error_flags; // write to clear +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +index e90c38044432..aec320d4e945 100644 +--- a/drivers/hid/ithc/ithc.h ++++ b/drivers/hid/ithc/ithc.h +@@ -14,6 +14,8 @@ + #include + #include + #include ++#include ++#include + + #define DEVNAME "ithc" + #define DEVFULLNAME "Intel Touch Host Controller" +@@ -46,8 +48,10 @@ + #define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 + #define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 + // Meteor Lake +-#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 +-#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b + + struct ithc; + +@@ -63,6 +67,7 @@ struct ithc { + struct pci_dev *pci; + int irq; + struct task_struct *poll_thread; ++ struct timer_list idle_timer; + + struct ithc_registers __iomem *regs; + struct ithc_registers *prev_regs; // for debugging +-- +2.45.2 diff --git a/patches/6.9/0007-surface-sam.patch b/patches/6.9/0007-surface-sam.patch index 41e4665cef..d1cf25f042 100644 --- a/patches/6.9/0007-surface-sam.patch +++ b/patches/6.9/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 4dd4e50694677d063eceb17e44b24fd0473df390 Mon Sep 17 00:00:00 2001 +From cebca0467ba24265a1e51432ac35beac33891a6e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 May 2024 16:15:49 +0200 Subject: [PATCH] serial: Clear UPF_DEAD before calling @@ -46,7 +46,7 @@ Patchset: surface-sam 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c -index c476d884356db..b47a277978a0b 100644 +index c476d884356d..b47a277978a0 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3211,6 +3211,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u @@ -77,9 +77,9 @@ index c476d884356db..b47a277978a0b 100644 return 0; -- -2.45.1 +2.45.2 -From f467f4373c2620fbf27c1ce0246bad8437034e33 Mon Sep 17 00:00:00 2001 +From e453ab926ce00cd87c30f55342031d4f3bf78e53 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 5 May 2024 21:07:50 +0800 Subject: [PATCH] platform/surface: aggregator: Log critical errors during SAM @@ -101,7 +101,7 @@ Patchset: surface-sam 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c -index ba550eaa06fcf..797d0645bd77f 100644 +index ba550eaa06fc..797d0645bd77 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -618,15 +618,17 @@ static const struct acpi_gpio_mapping ssam_acpi_gpios[] = { @@ -213,9 +213,9 @@ index ba550eaa06fcf..797d0645bd77f 100644 ssam_controller_lock(ctrl); ssam_controller_shutdown(ctrl); -- -2.45.1 +2.45.2 -From aa3d6b4b41566cbb68ba342463fee27924238b30 Mon Sep 17 00:00:00 2001 +From d3ddbc07009ade7bd60e9575b4d280e44c8c2f63 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 19 Apr 2024 20:41:47 +0200 Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is @@ -254,7 +254,7 @@ Patchset: surface-sam 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c -index 7fc602e01487d..7e89f547999b2 100644 +index 7fc602e01487..7e89f547999b 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) @@ -268,9 +268,9 @@ index 7fc602e01487d..7e89f547999b2 100644 /* * Note: New events could still have been received after the previous -- -2.45.1 +2.45.2 -From dd4678d91fa59cdf247be667fa64b8959029123d Mon Sep 17 00:00:00 2001 +From 46aeacf7b116bd6e1711b1678f8c8c9d631e95c9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Oct 2023 14:57:11 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -287,7 +287,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 035d6b4105cd6..74688a2ed4b2e 100644 +index 035d6b4105cd..74688a2ed4b2 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -374,6 +374,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { @@ -301,9 +301,9 @@ index 035d6b4105cd6..74688a2ed4b2e 100644 { "MSHW0123", (unsigned long)ssam_node_group_sls }, -- -2.45.1 +2.45.2 -From 3598d00445216e0b1b0b3e4141c5a2f359bf19c4 Mon Sep 17 00:00:00 2001 +From e42a81ec22305c91f44562c0386f651dfdc48db1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 19:47:00 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -321,7 +321,7 @@ Patchset: surface-sam 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 74688a2ed4b2e..f02a933160ff2 100644 +index 74688a2ed4b2..f02a933160ff 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -253,8 +253,8 @@ static const struct software_node *ssam_node_group_sl5[] = { @@ -371,9 +371,9 @@ index 74688a2ed4b2e..f02a933160ff2 100644 { }, }; -- -2.45.1 +2.45.2 -From eab61a4d3b4de4f3f61789748ecff660b07fbf8b Mon Sep 17 00:00:00 2001 +From 779ad78ae568b1bf03927655133b23bdee5fc77c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 20:05:57 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -391,7 +391,7 @@ Patchset: surface-sam 1 file changed, 19 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index f02a933160ff2..34df1bdad83bd 100644 +index f02a933160ff..34df1bdad83b 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -253,6 +253,22 @@ static const struct software_node *ssam_node_group_sl5[] = { @@ -428,9 +428,9 @@ index f02a933160ff2..34df1bdad83bd 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.45.1 +2.45.2 -From 1b6e5187d5961bd4bf4aa939426f0dfa9f01abd8 Mon Sep 17 00:00:00 2001 +From 4a7f3f74a7d92f3e0567f7e876e77bf7c8bbcf6d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -452,7 +452,7 @@ Patchset: surface-sam create mode 100644 drivers/hwmon/surface_temp.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 83945397b6eb1..338ef73c96a3a 100644 +index 83945397b6eb..338ef73c96a3 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2070,6 +2070,16 @@ config SENSORS_SURFACE_FAN @@ -473,7 +473,7 @@ index 83945397b6eb1..338ef73c96a3a 100644 tristate "Texas Instruments ADC128D818" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 5c31808f6378d..de8bc99719e63 100644 +index 5c31808f6378..de8bc99719e6 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -208,6 +208,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o @@ -486,7 +486,7 @@ index 5c31808f6378d..de8bc99719e63 100644 obj-$(CONFIG_SENSORS_TC74) += tc74.o diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c new file mode 100644 -index 0000000000000..48c3e826713f6 +index 000000000000..48c3e826713f --- /dev/null +++ b/drivers/hwmon/surface_temp.c @@ -0,0 +1,165 @@ @@ -656,9 +656,9 @@ index 0000000000000..48c3e826713f6 +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.45.1 +2.45.2 -From 5e8b9e18c1502bd5371a42014b104e91467a3437 Mon Sep 17 00:00:00 2001 +From 98e9eaae15a93f4dbe3898d3c188e710b791528a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -676,7 +676,7 @@ Patchset: surface-sam 1 file changed, 96 insertions(+), 17 deletions(-) diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c -index 48c3e826713f6..4c08926139dbf 100644 +index 48c3e826713f..4c08926139db 100644 --- a/drivers/hwmon/surface_temp.c +++ b/drivers/hwmon/surface_temp.c @@ -17,6 +17,27 @@ @@ -851,9 +851,9 @@ index 48c3e826713f6..4c08926139dbf 100644 "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, NULL); -- -2.45.1 +2.45.2 -From 1e3af9982108daf50b030c5672df1f2791107608 Mon Sep 17 00:00:00 2001 +From fdf1850fe9d4ee229a5602361be23c126ce65c8a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:21:12 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -869,7 +869,7 @@ Patchset: surface-sam 1 file changed, 7 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 34df1bdad83bd..c0bf0cadcd258 100644 +index 34df1bdad83b..c0bf0cadcd25 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = { @@ -894,9 +894,9 @@ index 34df1bdad83bd..c0bf0cadcd258 100644 &ssam_node_pos_tablet_switch, &ssam_node_hid_kip_keyboard, -- -2.45.1 +2.45.2 -From fe8e2664ddcf80418be9e2f4ae3b9211257b6647 Mon Sep 17 00:00:00 2001 +From c98dd80f6541a1bd7108324f65d77a04a6978e39 Mon Sep 17 00:00:00 2001 From: Ivor Wanders Date: Sat, 16 Dec 2023 15:56:39 -0500 Subject: [PATCH] platform/surface: platform_profile: add fan profile switching @@ -913,7 +913,7 @@ Patchset: surface-sam 2 files changed, 100 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index c0bf0cadcd258..07a4c4e1120d3 100644 +index c0bf0cadcd25..07a4c4e1120d 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -68,8 +68,8 @@ static const struct software_node ssam_node_bat_sb3base = { @@ -1039,7 +1039,7 @@ index c0bf0cadcd258..07a4c4e1120d3 100644 &ssam_node_fan_speed, &ssam_node_pos_tablet_switch, diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c -index a5a3941b3f43a..e54d0a8f7daa5 100644 +index a5a3941b3f43..e54d0a8f7daa 100644 --- a/drivers/platform/surface/surface_platform_profile.c +++ b/drivers/platform/surface/surface_platform_profile.c @@ -1,7 +1,7 @@ @@ -1221,9 +1221,9 @@ index a5a3941b3f43a..e54d0a8f7daa5 100644 set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices); set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices); -- -2.45.1 +2.45.2 -From a36158d7724a8799dc53a8605f22d368d52d3bc5 Mon Sep 17 00:00:00 2001 +From 4adc9fe7e3e43927845ff1711d8f0a7c0a3c7e74 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:47:47 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -1235,7 +1235,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 07a4c4e1120d3..4dc79f791d390 100644 +index 07a4c4e1120d..4dc79f791d39 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -265,7 +265,9 @@ static const struct software_node *ssam_node_group_sl5[] = { @@ -1250,9 +1250,9 @@ index 07a4c4e1120d3..4dc79f791d390 100644 &ssam_node_hid_main_touchpad, &ssam_node_hid_main_iid5, -- -2.45.1 +2.45.2 -From ed9d1558fb33c0654e51457081b231e24bab480e Mon Sep 17 00:00:00 2001 +From df74cd4f195731eec0d7423b9b5ac5ad54e66206 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:48:02 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -1264,7 +1264,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 4dc79f791d390..77f903a04d128 100644 +index 4dc79f791d39..77f903a04d12 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -312,7 +312,9 @@ static const struct software_node *ssam_node_group_sls2[] = { @@ -1279,9 +1279,9 @@ index 4dc79f791d390..77f903a04d128 100644 &ssam_node_hid_sam_keyboard, &ssam_node_hid_sam_penstash, -- -2.45.1 +2.45.2 -From 72c97a89faddb83b43940ae213db3d96bbd14210 Mon Sep 17 00:00:00 2001 +From fbda016e6525668c554714feb8aa09e1baa3d174 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 28 Jun 2024 22:31:37 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Support for @@ -1293,7 +1293,7 @@ Patchset: surface-sam 1 file changed, 22 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 77f903a04d128..7d01d989d2a49 100644 +index 77f903a04d12..7d01d989d2a4 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -377,6 +377,25 @@ static const struct software_node *ssam_node_group_sp9[] = { @@ -1333,5 +1333,5 @@ index 77f903a04d128..7d01d989d2a49 100644 { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0008-surface-sam-over-hid.patch b/patches/6.9/0008-surface-sam-over-hid.patch index 4fa7cb11d6..31c36da0e2 100644 --- a/patches/6.9/0008-surface-sam-over-hid.patch +++ b/patches/6.9/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 62692a1aeb782ea036a05638ea726e1f3ca5d355 Mon Sep 17 00:00:00 2001 +From 7585229ad1aea953568798708fc2ead8cb90f63d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,7 +55,7 @@ Patchset: surface-sam-over-hid 1 file changed, 35 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index 14ae0cfc325ef..a3a9f81fb47ff 100644 +index 14ae0cfc325e..a3a9f81fb47f 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -639,6 +639,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, @@ -108,9 +108,9 @@ index 14ae0cfc325ef..a3a9f81fb47ff 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.45.1 +2.45.2 -From 7e84459d76ac641f836ed4831446be21df1ebee7 Mon Sep 17 00:00:00 2001 +From 801a75c7cc5bef355d1e631a44ae5633859b7846 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -133,7 +133,7 @@ Patchset: surface-sam-over-hid create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index b629e82af97c0..68656e8f309ed 100644 +index b629e82af97c..68656e8f309e 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH @@ -151,7 +151,7 @@ index b629e82af97c0..68656e8f309ed 100644 tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939bf..7efcd0cdb5329 100644 +index 53344330939b..7efcd0cdb532 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o @@ -164,7 +164,7 @@ index 53344330939bf..7efcd0cdb5329 100644 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 0000000000000..8b816ed8f35c6 +index 000000000000..8b816ed8f35c --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c @@ -0,0 +1,162 @@ @@ -331,5 +331,5 @@ index 0000000000000..8b816ed8f35c6 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0009-surface-button.patch b/patches/6.9/0009-surface-button.patch index 282c3c4fce..86091b1d2f 100644 --- a/patches/6.9/0009-surface-button.patch +++ b/patches/6.9/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 9d868315b886f83d0eb887d0a5ffadcb90788cea Mon Sep 17 00:00:00 2001 +From a012f0cf803890100e9f94b0f7b6407a53878f3c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -20,7 +20,7 @@ Patchset: surface-button 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index f6d060377d189..b8603f74eb286 100644 +index f6d060377d18..b8603f74eb28 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -73,9 +73,9 @@ index f6d060377d189..b8603f74eb286 100644 /* -- -2.45.1 +2.45.2 -From 2bb3998d481e605b9733230e1dbf2a7d6ba83999 Mon Sep 17 00:00:00 2001 +From 5cd243c3828123961c317d7fa72f87757b4309ef Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -96,7 +96,7 @@ Patchset: surface-button 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979cd..4240c98ca2265 100644 +index 2755601f979c..4240c98ca226 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) @@ -145,5 +145,5 @@ index 2755601f979cd..4240c98ca2265 100644 -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0010-surface-typecover.patch b/patches/6.9/0010-surface-typecover.patch index 8597657857..c882bd64c6 100644 --- a/patches/6.9/0010-surface-typecover.patch +++ b/patches/6.9/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 85296a664c811c04159d9711aa5b473bb469f55c Mon Sep 17 00:00:00 2001 +From 8337e937c2495cd8b9de9b44f9f64c2817904788 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 13171454f9591..a83beefd25f3f 100644 +index 13171454f959..a83beefd25f3 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index 13171454f9591..a83beefd25f3f 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.45.1 +2.45.2 -From 8335c380e55c3640cbd9342c34be2c901d837413 Mon Sep 17 00:00:00 2001 +From 9bf4f93024adfd53daffce089a685fcc5d6d5d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 56fc78841f245..a266449065a0a 100644 +index 56fc78841f24..a266449065a0 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -270,9 +270,9 @@ index 56fc78841f245..a266449065a0a 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.45.1 +2.45.2 -From c54e07fc833334829c1ba249683337e3e09ec212 Mon Sep 17 00:00:00 2001 +From afee306eb14e58d48ddac5e2807d1e3ddb532d7f Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -301,7 +301,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index a266449065a0a..060c706e936ac 100644 +index a266449065a0..060c706e936a 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -569,5 +569,5 @@ index a266449065a0a..060c706e936ac 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0011-surface-shutdown.patch b/patches/6.9/0011-surface-shutdown.patch index f962211474..17954bdc41 100644 --- a/patches/6.9/0011-surface-shutdown.patch +++ b/patches/6.9/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 2426c81454db39a94e544b8c29eaf3ca4cbd5230 Mon Sep 17 00:00:00 2001 +From 6ab472fbfe2677b038998f6482da35a7daf3c14d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index af2996d0d17ff..3ce0fb61257dc 100644 +index af2996d0d17f..3ce0fb61257d 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,7 +37,7 @@ index af2996d0d17ff..3ce0fb61257dc 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index eff7f5df08e27..d1cb4ff3ebc57 100644 +index eff7f5df08e2..d1cb4ff3ebc5 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6253,3 +6253,39 @@ static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev) @@ -81,7 +81,7 @@ index eff7f5df08e27..d1cb4ff3ebc57 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 6f9c5ed5eb3ba..01ec9872f2bc4 100644 +index 6f9c5ed5eb3b..01ec9872f2bc 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -465,6 +465,7 @@ struct pci_dev { @@ -93,5 +93,5 @@ index 6f9c5ed5eb3ba..01ec9872f2bc4 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0012-surface-gpe.patch b/patches/6.9/0012-surface-gpe.patch index 0729613bd7..0fe3fd90c5 100644 --- a/patches/6.9/0012-surface-gpe.patch +++ b/patches/6.9/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 0d62f4e462753400db41bd4afe964c79fbc5beeb Mon Sep 17 00:00:00 2001 +From 453898d99903c0e2a3c9b9b7f297abcb1af80d25 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -12,7 +12,7 @@ Patchset: surface-gpe 1 file changed, 17 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index 62fd4004db31a..103fc4468262a 100644 +index 62fd4004db31..103fc4468262 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { @@ -47,5 +47,5 @@ index 62fd4004db31a..103fc4468262a 100644 .ident = "Surface Book 1", .matches = { -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0013-cameras.patch b/patches/6.9/0013-cameras.patch index 45577ca517..2a6d0cc43c 100644 --- a/patches/6.9/0013-cameras.patch +++ b/patches/6.9/0013-cameras.patch @@ -1,4 +1,4 @@ -From 594b923f6a4571195fa63773639646bed2e2bb4e Mon Sep 17 00:00:00 2001 +From 2c667679a6694ea9720c30be32ba73977638ac3a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,7 +58,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index d1464324de951..5d865a34dd9db 100644 +index d1464324de95..5d865a34dd9d 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2181,6 +2181,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, @@ -72,9 +72,9 @@ index d1464324de951..5d865a34dd9db 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.45.1 +2.45.2 -From fb80060df68ffb77d006dffeb0d799b6b463e48c Mon Sep 17 00:00:00 2001 +From 0ac07f51d4c870ab988a572a9bdf9e3dde99ae46 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 61bc54299a591..a61af0f4e9fce 100644 +index 61bc54299a59..a61af0f4e9fc 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -182,9 +182,9 @@ index 61bc54299a591..a61af0f4e9fce 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.45.1 +2.45.2 -From eb3ed16ab7a069d5ecc11f6a2211caca3c574c5c Mon Sep 17 00:00:00 2001 +From 1c90833561276f2ca96a844a980a4660255fd241 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -201,7 +201,7 @@ Patchset: cameras 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 1e107fd49f828..e3e1696e7f0ee 100644 +index 1e107fd49f82..e3e1696e7f0e 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) @@ -219,9 +219,9 @@ index 1e107fd49f828..e3e1696e7f0ee 100644 return 0; -- -2.45.1 +2.45.2 -From 29b7931d1f73183b14b407ee2f6d1e3cdf8d2e23 Mon Sep 17 00:00:00 2001 +From 9a9c937d189290f66f1744119731887a3acc6d10 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -243,7 +243,7 @@ Patchset: cameras 1 file changed, 14 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 07b302e093407..1d3097bc7e487 100644 +index 07b302e09340..1d3097bc7e48 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 @@ -274,9 +274,9 @@ index 07b302e093407..1d3097bc7e487 100644 agpio, func, polarity); if (ret) -- -2.45.1 +2.45.2 -From 6319fff6505329f27cc622fb2a0b604c04ed3bd2 Mon Sep 17 00:00:00 2001 +From b329ea16ddeae06460a32495f79cd82d1c58ee65 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -291,7 +291,7 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf5..9c1292ca85522 100644 +index 30f61e04ecaf..9c1292ca8552 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) @@ -313,9 +313,9 @@ index 30f61e04ecaf5..9c1292ca85522 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.45.1 +2.45.2 -From 8fe1d3b0660385751147ba14b70bf785de405768 Mon Sep 17 00:00:00 2001 +From 4b407381f7a1272abf62bd19a32240b4abbb5128 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -334,7 +334,7 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index 4bb073587817c..cbcbf91db640a 100644 +index 4bb073587817..cbcbf91db640 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -792,6 +792,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) @@ -349,7 +349,7 @@ index 4bb073587817c..cbcbf91db640a 100644 * No reference taken. The reference is held by the device (struct * v4l2_subdev.dev), and async sub-device does not exist independently diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index 89c7192148dfb..44eca113e7727 100644 +index 89c7192148df..44eca113e772 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) @@ -364,9 +364,9 @@ index 89c7192148dfb..44eca113e7727 100644 if (ret < 0) goto out_cleanup; -- -2.45.1 +2.45.2 -From 801bb9a48ddc1eb3ce5353d0d5c7315851efcce1 Mon Sep 17 00:00:00 2001 +From 1058d4acabef10a3e2002f4c6017cc9f83300ec9 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -382,7 +382,7 @@ Patchset: cameras 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index e3e1696e7f0ee..423dc555093f7 100644 +index e3e1696e7f0e..423dc555093f 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -405,9 +405,9 @@ index e3e1696e7f0ee..423dc555093f7 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.45.1 +2.45.2 -From b5bf7bf96d471674edb3adc1ca037d22104a8151 Mon Sep 17 00:00:00 2001 +From 0c84792426ef55475cf21abe08692e849baea648 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -425,7 +425,7 @@ Patchset: cameras 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db00..2d2abb25b944f 100644 +index 7807fa329db0..2d2abb25b944 100644 --- a/include/linux/mfd/tps68470.h +++ b/include/linux/mfd/tps68470.h @@ -34,6 +34,7 @@ @@ -446,9 +446,9 @@ index 7807fa329db00..2d2abb25b944f 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.45.1 +2.45.2 -From eb8c1aedc9f1b8ea35d575a3d5ff7cec5a038945 Mon Sep 17 00:00:00 2001 +From bcdf2d2c87ec937d77fad091d249f321d9adc727 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -471,7 +471,7 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 05e6af88b88cd..c120eb0b5aa8e 100644 +index 05e6af88b88c..c120eb0b5aa8 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -909,6 +909,18 @@ config LEDS_TPS6105X @@ -494,7 +494,7 @@ index 05e6af88b88cd..c120eb0b5aa8e 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index effdfc6f1e951..6ce609b2cdac6 100644 +index effdfc6f1e95..6ce609b2cdac 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o @@ -507,7 +507,7 @@ index effdfc6f1e951..6ce609b2cdac6 100644 obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c new file mode 100644 -index 0000000000000..35aeb5db89c8f +index 000000000000..35aeb5db89c8 --- /dev/null +++ b/drivers/leds/leds-tps68470.c @@ -0,0 +1,185 @@ @@ -697,9 +697,9 @@ index 0000000000000..35aeb5db89c8f +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.45.1 +2.45.2 -From f4f947cb92583d5358a128c8d9f3508b5af9124c Mon Sep 17 00:00:00 2001 +From 95b7370aee5aed2b2cad5baf8a6835b47fd2d8a5 Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -713,7 +713,7 @@ Patchset: cameras 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c -index 3df58eb3e8822..81aff2d5d8988 100644 +index 3df58eb3e882..81aff2d5d898 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -538,18 +538,18 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq) @@ -744,9 +744,9 @@ index 3df58eb3e8822..81aff2d5d8988 100644 r = imgu_s_stream(imgu, false); if (!r) -- -2.45.1 +2.45.2 -From c3495660cd36f2dca4371530ae94a42adab57f71 Mon Sep 17 00:00:00 2001 +From 7078234b232f3ebc7b79b14e385c70a3bfd31b4d Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -762,7 +762,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928c..0094cfda57ea8 100644 +index c626ed845928..0094cfda57ea 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c @@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) @@ -776,5 +776,5 @@ index c626ed845928c..0094cfda57ea8 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0014-amd-gpio.patch b/patches/6.9/0014-amd-gpio.patch index 28b92fdb11..09a39a3f43 100644 --- a/patches/6.9/0014-amd-gpio.patch +++ b/patches/6.9/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 7b3fa7073f0ce137fa8ed1192e37c48772705052 Mon Sep 17 00:00:00 2001 +From e77ba620d8f52dacab1b3515fe05617fd7b28141 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 4bf82dbd2a6b5..7a8cb090c6568 100644 +index 4bf82dbd2a6b..7a8cb090c656 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -63,9 +63,9 @@ index 4bf82dbd2a6b5..7a8cb090c6568 100644 mp_config_acpi_legacy_irqs(); -- -2.45.1 +2.45.2 -From bad564b5cc50539fe028ccac8b67b0896fbde7fa Mon Sep 17 00:00:00 2001 +From 07d6fb46ee1d967a8882c85e0abc0ce12dffbf1d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,7 +80,7 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 7a8cb090c6568..0faafc323e673 100644 +index 7a8cb090c656..0faafc323e67 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1219,12 +1219,19 @@ static void __init mp_config_acpi_legacy_irqs(void) @@ -105,5 +105,5 @@ index 7a8cb090c6568..0faafc323e673 100644 }; -- -2.45.1 +2.45.2 diff --git a/patches/6.9/0015-rtc.patch b/patches/6.9/0015-rtc.patch index 08b2bd41a1..90bdf64689 100644 --- a/patches/6.9/0015-rtc.patch +++ b/patches/6.9/0015-rtc.patch @@ -1,4 +1,4 @@ -From 0d942a7b3bc0613de7ae4c7583bd9625e75c203a Mon Sep 17 00:00:00 2001 +From d42ba535b58d5fb2325b26fba1460435afa86dac Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 1d670dbe4d1dd..71c9e375ca1ca 100644 +index 1d670dbe4d1d..71c9e375ca1c 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -432,6 +432,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, @@ -106,5 +106,5 @@ index 1d670dbe4d1dd..71c9e375ca1ca 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.45.1 +2.45.2 From d44187ae85db717bb9ad91931ec21ff3bd83f5e6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Aug 2024 16:37:17 +0200 Subject: [PATCH 042/236] Add patches for 6.10 Derived from latest 6.9 patches Links: - kernel: https://github.com/linux-surface/kernel/commit/17c8b97354ad07e4f34308b0bb72792245bf50d8 - tree-devel: https://github.com/linux-surface/kernel/commits/v6.10-surface-devel - tree-patches: https://github.com/linux-surface/kernel/commits/v6.10-surface --- configs/surface-6.10.config | 81 + patches/6.10/0001-secureboot.patch | 37 + patches/6.10/0002-surface3-oemb.patch | 101 + patches/6.10/0003-mwifiex.patch | 400 +++ patches/6.10/0004-ath10k.patch | 120 + patches/6.10/0005-ipts.patch | 3241 ++++++++++++++++++ patches/6.10/0006-ithc.patch | 2771 +++++++++++++++ patches/6.10/0007-surface-sam.patch | 750 ++++ patches/6.10/0008-surface-sam-over-hid.patch | 335 ++ patches/6.10/0009-surface-button.patch | 149 + patches/6.10/0010-surface-typecover.patch | 573 ++++ patches/6.10/0011-surface-shutdown.patch | 97 + patches/6.10/0012-surface-gpe.patch | 51 + patches/6.10/0013-cameras.patch | 780 +++++ patches/6.10/0014-amd-gpio.patch | 109 + patches/6.10/0015-rtc.patch | 110 + 16 files changed, 9705 insertions(+) create mode 100644 configs/surface-6.10.config create mode 100644 patches/6.10/0001-secureboot.patch create mode 100644 patches/6.10/0002-surface3-oemb.patch create mode 100644 patches/6.10/0003-mwifiex.patch create mode 100644 patches/6.10/0004-ath10k.patch create mode 100644 patches/6.10/0005-ipts.patch create mode 100644 patches/6.10/0006-ithc.patch create mode 100644 patches/6.10/0007-surface-sam.patch create mode 100644 patches/6.10/0008-surface-sam-over-hid.patch create mode 100644 patches/6.10/0009-surface-button.patch create mode 100644 patches/6.10/0010-surface-typecover.patch create mode 100644 patches/6.10/0011-surface-shutdown.patch create mode 100644 patches/6.10/0012-surface-gpe.patch create mode 100644 patches/6.10/0013-cameras.patch create mode 100644 patches/6.10/0014-amd-gpio.patch create mode 100644 patches/6.10/0015-rtc.patch diff --git a/configs/surface-6.10.config b/configs/surface-6.10.config new file mode 100644 index 0000000000..05628a9957 --- /dev/null +++ b/configs/surface-6.10.config @@ -0,0 +1,81 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m diff --git a/patches/6.10/0001-secureboot.patch b/patches/6.10/0001-secureboot.patch new file mode 100644 index 0000000000..c3ee33d860 --- /dev/null +++ b/patches/6.10/0001-secureboot.patch @@ -0,0 +1,37 @@ +From fa4500c4ae1546dba5d5e4fbada8e6d0406adab0 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.45.2 + diff --git a/patches/6.10/0002-surface3-oemb.patch b/patches/6.10/0002-surface3-oemb.patch new file mode 100644 index 0000000000..ef149645aa --- /dev/null +++ b/patches/6.10/0002-surface3-oemb.patch @@ -0,0 +1,101 @@ +From b161e7d8c1f16ef72ed5195aa97e6357e06bdc4e Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-oemb +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index c15ed7a12784..1ec8edb5aafa 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index 5e2ec60e2954..207868c699f2 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.45.2 + diff --git a/patches/6.10/0003-mwifiex.patch b/patches/6.10/0003-mwifiex.patch new file mode 100644 index 0000000000..6c38a11244 --- /dev/null +++ b/patches/6.10/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From 2497b1ba9fa349ddf764c38c46160a785a5f3475 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.45.2 + +From 52c3a74193a1e37e241dc8a8cef0a71e843a29b5 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.45.2 + +From 338d5143d47a9de3d5a25f1fa203f6b6a95864ef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 789c492df6fa..1e766b6c1f9a 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -468,6 +469,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -4448,6 +4450,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.45.2 + diff --git a/patches/6.10/0004-ath10k.patch b/patches/6.10/0004-ath10k.patch new file mode 100644 index 0000000000..64d1e6abf9 --- /dev/null +++ b/patches/6.10/0004-ath10k.patch @@ -0,0 +1,120 @@ +From 5030f889081c8676ae652623ad86b797b05d7221 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index bdf0552cd1c3..e062cc687689 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -39,6 +39,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -51,6 +54,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -60,6 +66,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -914,6 +923,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -928,6 +973,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.45.2 + diff --git a/patches/6.10/0005-ipts.patch b/patches/6.10/0005-ipts.patch new file mode 100644 index 0000000000..78f53c16ca --- /dev/null +++ b/patches/6.10/0005-ipts.patch @@ -0,0 +1,3241 @@ +From 318ef833ea6bf3a2ef7566bad79931b216bd7423 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6589635f8ba3..a1df48a434e2 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.45.2 + +From ddcd34d797494f38ba7be0d9e46a919fda557576 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index f55ec1fd7942..8d95579436a9 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -40,6 +40,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -217,12 +222,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -2195,6 +2202,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2495,6 +2505,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + ret = si_domain_init(hw_pass_through); +@@ -4617,6 +4630,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4652,6 +4677,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.45.2 + +From 6ff2cce19a707fb565e9aebf9fb2b00fe845a46a Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 08446c89eff6..ccddfba86004 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1367,4 +1367,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + + source "drivers/hid/surface-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index ce71b53ea6c5..de41081b6a5a 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -171,3 +171,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.45.2 + diff --git a/patches/6.10/0006-ithc.patch b/patches/6.10/0006-ithc.patch new file mode 100644 index 0000000000..cf713b3f76 --- /dev/null +++ b/patches/6.10/0006-ithc.patch @@ -0,0 +1,2771 @@ +From 52e90ab224f06fd648ca85cd43a91670a9a4e683 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index e4a70886678c..961a33b87c24 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.45.2 + +From a5da515376d209ea8610fed94888f48d9b64387f Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index ccddfba86004..8e2ea8175bfb 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1369,4 +1369,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index de41081b6a5a..9d156f1b3910 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,3 +173,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.45.2 + diff --git a/patches/6.10/0007-surface-sam.patch b/patches/6.10/0007-surface-sam.patch new file mode 100644 index 0000000000..11283a69a8 --- /dev/null +++ b/patches/6.10/0007-surface-sam.patch @@ -0,0 +1,750 @@ +From 5180e4810b868e0d3da85577b776a929cecf1d65 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 19 Apr 2024 20:41:47 +0200 +Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is + destroyed in probe + +There is a small window in ssam_serial_hub_probe() where the controller +is initialized but has not been started yet. Specifically, between +ssam_controller_init() and ssam_controller_start(). Any failure in this +window, for example caused by a failure of serdev_device_open(), +currently results in an incorrect warning being emitted. + +In particular, any failure in this window results in the controller +being destroyed via ssam_controller_destroy(). This function checks the +state of the controller and, in an attempt to validate that the +controller has been cleanly shut down before we try and deallocate any +resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. + +However, since we have only just initialized the controller and have not +yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this +is the only point at which the controller has this state, as it will +change after we start the controller with ssam_controller_start() and +never revert back. Further, at this point no communication has taken +place and the sender and receiver threads have not been started yet (and +we may not even have an open serdev device either). + +Therefore, it is perfectly safe to call ssam_controller_destroy() with a +state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the +warning currently being emitted is incorrect. Fix it by extending the +check. + +Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/platform/surface/aggregator/controller.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c +index 7fc602e01487..7e89f547999b 100644 +--- a/drivers/platform/surface/aggregator/controller.c ++++ b/drivers/platform/surface/aggregator/controller.c +@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) + if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) + return; + +- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); ++ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && ++ ctrl->state != SSAM_CONTROLLER_INITIALIZED); + + /* + * Note: New events could still have been received after the previous +-- +2.45.2 + +From 144dbc865c07df0290009d509b31635aac53a907 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 22 Oct 2023 14:57:11 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add support for + Surface Laptop Go 3 + +Add SAM client device nodes for the Surface Laptop Go 3. It seems to use +the same SAM client devices as the Surface Laptop Go 1 and 2, so re-use +their node group. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 1c4d74db08c9..f826489dc69d 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -395,6 +395,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Laptop Go 2 */ + { "MSHW0290", (unsigned long)ssam_node_group_slg1 }, + ++ /* Surface Laptop Go 3 */ ++ { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, ++ + /* Surface Laptop Studio */ + { "MSHW0123", (unsigned long)ssam_node_group_sls }, + +-- +2.45.2 + +From 7b906ae84a56322a5098c77a774f5fb00b4318a5 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Mon, 20 Nov 2023 19:47:00 +0100 +Subject: [PATCH] platform/surface: aggregator_registry: Add support for + Surface Laptop Studio 2 + +Add SAM client device nodes for the Surface Laptop Studio 2 (SLS2). The +SLS2 is quite similar to the SLS1, but it does not provide the touchpad +as a SAM-HID device. Therefore, add a new node group for the SLS2 and +update the comments accordingly + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + .../surface/surface_aggregator_registry.c | 25 ++++++++++++++++--- + 1 file changed, 21 insertions(+), 4 deletions(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index f826489dc69d..ef59a7b66667 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -273,8 +273,8 @@ static const struct software_node *ssam_node_group_sl5[] = { + NULL, + }; + +-/* Devices for Surface Laptop Studio. */ +-static const struct software_node *ssam_node_group_sls[] = { ++/* Devices for Surface Laptop Studio 1. */ ++static const struct software_node *ssam_node_group_sls1[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +@@ -289,6 +289,20 @@ static const struct software_node *ssam_node_group_sls[] = { + NULL, + }; + ++/* Devices for Surface Laptop Studio 2. */ ++static const struct software_node *ssam_node_group_sls2[] = { ++ &ssam_node_root, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ &ssam_node_tmp_pprof, ++ &ssam_node_pos_tablet_switch, ++ &ssam_node_hid_sam_keyboard, ++ &ssam_node_hid_sam_penstash, ++ &ssam_node_hid_sam_sensors, ++ &ssam_node_hid_sam_ucm_ucsi, ++ NULL, ++}; ++ + /* Devices for Surface Laptop Go. */ + static const struct software_node *ssam_node_group_slg1[] = { + &ssam_node_root, +@@ -398,8 +412,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Laptop Go 3 */ + { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, + +- /* Surface Laptop Studio */ +- { "MSHW0123", (unsigned long)ssam_node_group_sls }, ++ /* Surface Laptop Studio 1 */ ++ { "MSHW0123", (unsigned long)ssam_node_group_sls1 }, ++ ++ /* Surface Laptop Studio 2 */ ++ { "MSHW0360", (unsigned long)ssam_node_group_sls2 }, + + { }, + }; +-- +2.45.2 + +From d602c3714f0cc654b90de7800f844d6201eaa66b Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 20:05:57 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add support for + Surface Laptop 6 + +Add SAM client device nodes for the Surface Laptop Studio 6 (SL6). The +SL6 is similar to the SL5, with the typical battery/AC, platform +profile, and HID nodes. It also has support for the newly supported fan +interface. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + .../surface/surface_aggregator_registry.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index ef59a7b66667..70a2ea5a1957 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -273,6 +273,22 @@ static const struct software_node *ssam_node_group_sl5[] = { + NULL, + }; + ++/* Devices for Surface Laptop 6. */ ++static const struct software_node *ssam_node_group_sl6[] = { ++ &ssam_node_root, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, ++ &ssam_node_hid_main_keyboard, ++ &ssam_node_hid_main_touchpad, ++ &ssam_node_hid_main_iid5, ++ &ssam_node_hid_sam_sensors, ++ &ssam_node_hid_sam_ucm_ucsi, ++ NULL, ++}; ++ + /* Devices for Surface Laptop Studio 1. */ + static const struct software_node *ssam_node_group_sls1[] = { + &ssam_node_root, +@@ -403,6 +419,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Laptop 5 */ + { "MSHW0350", (unsigned long)ssam_node_group_sl5 }, + ++ /* Surface Laptop 6 */ ++ { "MSHW0530", (unsigned long)ssam_node_group_sl5 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.45.2 + +From 4bde7be038c7dced1b596c7d41e6f0bb3043d301 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 30 Dec 2023 18:07:54 +0100 +Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator + Module + +Some of the newer Microsoft Surface devices (such as the Surface Book +3 and Pro 9) have thermal sensors connected via the Surface Aggregator +Module (the embedded controller on those devices). Add a basic driver +to read out the temperature values of those sensors. + +Link: https://github.com/linux-surface/surface-aggregator-module/issues/59 +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/hwmon/Kconfig | 10 +++ + drivers/hwmon/Makefile | 1 + + drivers/hwmon/surface_temp.c | 165 +++++++++++++++++++++++++++++++++++ + 3 files changed, 176 insertions(+) + create mode 100644 drivers/hwmon/surface_temp.c + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index e14ae18a973b..76eabe3e4435 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -2093,6 +2093,16 @@ config SENSORS_SURFACE_FAN + + Select M or Y here, if you want to be able to read the fan's speed. + ++config SENSORS_SURFACE_TEMP ++ tristate "Microsoft Surface Thermal Sensor Driver" ++ depends on SURFACE_AGGREGATOR ++ help ++ Driver for monitoring thermal sensors connected via the Surface ++ Aggregator Module (embedded controller) on Microsoft Surface devices. ++ ++ This driver can also be built as a module. If so, the module ++ will be called surface_temp. ++ + config SENSORS_ADC128D818 + tristate "Texas Instruments ADC128D818" + depends on I2C +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index e3f25475d1f0..eff74ab7f720 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -209,6 +209,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o + obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o + obj-$(CONFIG_SENSORS_STTS751) += stts751.o + obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o ++obj-$(CONFIG_SENSORS_SURFACE_TEMP)+= surface_temp.o + obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o + obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o + obj-$(CONFIG_SENSORS_TC74) += tc74.o +diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c +new file mode 100644 +index 000000000000..48c3e826713f +--- /dev/null ++++ b/drivers/hwmon/surface_temp.c +@@ -0,0 +1,165 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Thermal sensor subsystem driver for Surface System Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2022-2023 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++/* -- SAM interface. -------------------------------------------------------- */ ++ ++SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x04, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x01, ++}); ++ ++static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors) ++{ ++ __le16 sensors_le; ++ int status; ++ ++ status = __ssam_tmp_get_available_sensors(sdev, &sensors_le); ++ if (status) ++ return status; ++ ++ *sensors = le16_to_cpu(sensors_le); ++ return 0; ++} ++ ++static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temperature) ++{ ++ __le16 temp_le; ++ int status; ++ ++ status = __ssam_tmp_get_temperature(sdev->ctrl, sdev->uid.target, iid, &temp_le); ++ if (status) ++ return status; ++ ++ /* Convert 1/10 °K to 1/1000 °C */ ++ *temperature = (le16_to_cpu(temp_le) - 2731) * 100L; ++ return 0; ++} ++ ++ ++/* -- Driver.---------------------------------------------------------------- */ ++ ++struct ssam_temp { ++ struct ssam_device *sdev; ++ s16 sensors; ++}; ++ ++static umode_t ssam_temp_hwmon_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct ssam_temp *ssam_temp = data; ++ ++ if (!(ssam_temp->sensors & BIT(channel))) ++ return 0; ++ ++ return 0444; ++} ++ ++static int ssam_temp_hwmon_read(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, long *value) ++{ ++ const struct ssam_temp *ssam_temp = dev_get_drvdata(dev); ++ ++ return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value); ++} ++ ++static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = { ++ HWMON_CHANNEL_INFO(chip, ++ HWMON_C_REGISTER_TZ), ++ /* We have at most 16 thermal sensor channels. */ ++ HWMON_CHANNEL_INFO(temp, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT), ++ NULL ++}; ++ ++static const struct hwmon_ops ssam_temp_hwmon_ops = { ++ .is_visible = ssam_temp_hwmon_is_visible, ++ .read = ssam_temp_hwmon_read, ++}; ++ ++static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = { ++ .ops = &ssam_temp_hwmon_ops, ++ .info = ssam_temp_hwmon_info, ++}; ++ ++static int ssam_temp_probe(struct ssam_device *sdev) ++{ ++ struct ssam_temp *ssam_temp; ++ struct device *hwmon_dev; ++ s16 sensors; ++ int status; ++ ++ status = ssam_tmp_get_available_sensors(sdev, &sensors); ++ if (status) ++ return status; ++ ++ ssam_temp = devm_kzalloc(&sdev->dev, sizeof(*ssam_temp), GFP_KERNEL); ++ if (!ssam_temp) ++ return -ENOMEM; ++ ++ ssam_temp->sdev = sdev; ++ ssam_temp->sensors = sensors; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev, ++ "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, ++ NULL); ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ return 0; ++} ++ ++static const struct ssam_device_id ssam_temp_match[] = { ++ { SSAM_SDEV(TMP, SAM, 0x00, 0x02) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, ssam_temp_match); ++ ++static struct ssam_device_driver ssam_temp = { ++ .probe = ssam_temp_probe, ++ .match_table = ssam_temp_match, ++ .driver = { ++ .name = "surface_temp", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(ssam_temp); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.45.2 + +From ae82a35c632785771ebe2ad7f48006a1eb8f6a91 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 30 Dec 2023 18:12:23 +0100 +Subject: [PATCH] hwmon: surface_temp: Add support for sensor names + +The thermal subsystem of the Surface Aggregator Module allows us to +query the names of the respective thermal sensors. Forward those to +userspace. + +Signed-off-by: Ivor Wanders +Co-Developed-by: Maximilian Luz +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/hwmon/surface_temp.c | 113 +++++++++++++++++++++++++++++------ + 1 file changed, 96 insertions(+), 17 deletions(-) + +diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c +index 48c3e826713f..4c08926139db 100644 +--- a/drivers/hwmon/surface_temp.c ++++ b/drivers/hwmon/surface_temp.c +@@ -17,6 +17,27 @@ + + /* -- SAM interface. -------------------------------------------------------- */ + ++/* ++ * Available sensors are indicated by a 16-bit bitfield, where a 1 marks the ++ * presence of a sensor. So we have at most 16 possible sensors/channels. ++ */ ++#define SSAM_TMP_SENSOR_MAX_COUNT 16 ++ ++/* ++ * All names observed so far are 6 characters long, but there's only ++ * zeros after the name, so perhaps they can be longer. This number reflects ++ * the maximum zero-padded space observed in the returned buffer. ++ */ ++#define SSAM_TMP_SENSOR_NAME_LENGTH 18 ++ ++struct ssam_tmp_get_name_rsp { ++ __le16 unknown1; ++ char unknown2; ++ char name[SSAM_TMP_SENSOR_NAME_LENGTH]; ++} __packed; ++ ++static_assert(sizeof(struct ssam_tmp_get_name_rsp) == 21); ++ + SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, { + .target_category = SSAM_SSH_TC_TMP, + .command_id = 0x04, +@@ -27,6 +48,11 @@ SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, { + .command_id = 0x01, + }); + ++SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_name, struct ssam_tmp_get_name_rsp, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x0e, ++}); ++ + static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors) + { + __le16 sensors_le; +@@ -54,12 +80,37 @@ static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temp + return 0; + } + ++static int ssam_tmp_get_name(struct ssam_device *sdev, u8 iid, char *buf, size_t buf_len) ++{ ++ struct ssam_tmp_get_name_rsp name_rsp; ++ int status; ++ ++ status = __ssam_tmp_get_name(sdev->ctrl, sdev->uid.target, iid, &name_rsp); ++ if (status) ++ return status; ++ ++ /* ++ * This should not fail unless the name in the returned struct is not ++ * null-terminated or someone changed something in the struct ++ * definitions above, since our buffer and struct have the same ++ * capacity by design. So if this fails blow this up with a warning. ++ * Since the more likely cause is that the returned string isn't ++ * null-terminated, we might have received garbage (as opposed to just ++ * an incomplete string), so also fail the function. ++ */ ++ status = strscpy(buf, name_rsp.name, buf_len); ++ WARN_ON(status < 0); ++ ++ return status < 0 ? status : 0; ++} ++ + + /* -- Driver.---------------------------------------------------------------- */ + + struct ssam_temp { + struct ssam_device *sdev; + s16 sensors; ++ char names[SSAM_TMP_SENSOR_MAX_COUNT][SSAM_TMP_SENSOR_NAME_LENGTH]; + }; + + static umode_t ssam_temp_hwmon_is_visible(const void *data, +@@ -83,33 +134,47 @@ static int ssam_temp_hwmon_read(struct device *dev, + return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value); + } + ++static int ssam_temp_hwmon_read_string(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, const char **str) ++{ ++ const struct ssam_temp *ssam_temp = dev_get_drvdata(dev); ++ ++ *str = ssam_temp->names[channel]; ++ return 0; ++} ++ + static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_REGISTER_TZ), +- /* We have at most 16 thermal sensor channels. */ ++ /* ++ * We have at most SSAM_TMP_SENSOR_MAX_COUNT = 16 thermal sensor ++ * channels. ++ */ + HWMON_CHANNEL_INFO(temp, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT), ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL), + NULL + }; + + static const struct hwmon_ops ssam_temp_hwmon_ops = { + .is_visible = ssam_temp_hwmon_is_visible, + .read = ssam_temp_hwmon_read, ++ .read_string = ssam_temp_hwmon_read_string, + }; + + static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = { +@@ -122,6 +187,7 @@ static int ssam_temp_probe(struct ssam_device *sdev) + struct ssam_temp *ssam_temp; + struct device *hwmon_dev; + s16 sensors; ++ int channel; + int status; + + status = ssam_tmp_get_available_sensors(sdev, &sensors); +@@ -135,6 +201,19 @@ static int ssam_temp_probe(struct ssam_device *sdev) + ssam_temp->sdev = sdev; + ssam_temp->sensors = sensors; + ++ /* Retrieve the name for each available sensor. */ ++ for (channel = 0; channel < SSAM_TMP_SENSOR_MAX_COUNT; channel++) ++ { ++ if (!(sensors & BIT(channel))) ++ continue; ++ ++ status = ssam_tmp_get_name(sdev, channel + 1, ++ ssam_temp->names[channel], ++ SSAM_TMP_SENSOR_NAME_LENGTH); ++ if (status) ++ return status; ++ } ++ + hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev, + "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, + NULL); +-- +2.45.2 + +From 6a80e0b93ce1d8cf9d1b7e383b4b951fb4908294 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Mon, 10 Jun 2024 21:47:47 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal + sensor support for Surface Laptop 5 + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 70a2ea5a1957..6b568804f70b 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -265,7 +265,9 @@ static const struct software_node *ssam_node_group_sl5[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_perf_profile, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, + &ssam_node_hid_main_keyboard, + &ssam_node_hid_main_touchpad, + &ssam_node_hid_main_iid5, +-- +2.45.2 + +From 3175ecd829a778ffef35956d8785877bb76fe4b0 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Mon, 10 Jun 2024 21:48:02 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal + sensor support for Surface Laptop Studio 2 + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 6b568804f70b..9046df95c043 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -312,7 +312,9 @@ static const struct software_node *ssam_node_group_sls2[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, +- &ssam_node_tmp_pprof, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, + &ssam_node_pos_tablet_switch, + &ssam_node_hid_sam_keyboard, + &ssam_node_hid_sam_penstash, +-- +2.45.2 + +From aeef49471d7ec17f243c685b85c0c870c99e9e3d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 28 Jun 2024 22:31:37 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Support for + Surface Pro 10 + +Patchset: surface-sam +--- + .../surface/surface_aggregator_registry.c | 22 +++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 9046df95c043..058f4edd8b66 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -377,6 +377,25 @@ static const struct software_node *ssam_node_group_sp9[] = { + NULL, + }; + ++/* Devices for Surface Pro 10 */ ++static const struct software_node *ssam_node_group_sp10[] = { ++ &ssam_node_root, ++ &ssam_node_hub_kip, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, ++ &ssam_node_pos_tablet_switch, ++ &ssam_node_hid_kip_keyboard, ++ &ssam_node_hid_kip_penstash, ++ &ssam_node_hid_kip_touchpad, ++ &ssam_node_hid_kip_fwupd, ++ &ssam_node_hid_sam_sensors, ++ &ssam_node_hid_sam_ucm_ucsi, ++ NULL, ++}; ++ + + /* -- SSAM platform/meta-hub driver. ---------------------------------------- */ + +@@ -399,6 +418,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Pro 9 */ + { "MSHW0343", (unsigned long)ssam_node_group_sp9 }, + ++ /* Surface Pro 10 */ ++ { "MSHW0510", (unsigned long)ssam_node_group_sp10 }, ++ + /* Surface Book 2 */ + { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, + +-- +2.45.2 + diff --git a/patches/6.10/0008-surface-sam-over-hid.patch b/patches/6.10/0008-surface-sam-over-hid.patch new file mode 100644 index 0000000000..5359c72309 --- /dev/null +++ b/patches/6.10/0008-surface-sam-over-hid.patch @@ -0,0 +1,335 @@ +From 56def3328ab5c84c33a87c062448f1f97e545282 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index 14ae0cfc325e..a3a9f81fb47f 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -639,6 +639,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret = AE_OK; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -740,6 +762,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.45.2 + +From 99ca5a4092ea27b42c256940694e13a8f2abd457 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 162 ++++++++++++++++++ + 3 files changed, 170 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..8b816ed8f35c +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,162 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef pr_fmt ++#undef pr_fmt ++#endif ++#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ ++ ++ ++static const guid_t dgpu_sw_guid = GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *ret; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ ret = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!ret) ++ return -EINVAL; ++ ++ ACPI_FREE(ret); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(void) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ pr_err("failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ if (buf.pointer) ++ ACPI_FREE(buf.pointer); ++ ++ pr_info("turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(void) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ pr_err("failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ if (buf.pointer) ++ ACPI_FREE(buf.pointer); ++ ++ pr_info("turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int status, value; ++ ++ status = kstrtoint(buf, 0, &value); ++ if (status < 0) ++ return status; ++ ++ if (value != 1) ++ return -EINVAL; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(); ++ else ++ status = sb1_dgpu_sw_hgof(); ++ ++ return status < 0 ? status : len; ++} ++ ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL, ++}; ++ ++static const struct attribute_group sb1_dgpu_sw_attr_group = { ++ .attrs = sb1_dgpu_sw_attrs, ++}; ++ ++ ++static int sb1_dgpu_sw_probe(struct platform_device *pdev) ++{ ++ return sysfs_create_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); ++} ++ ++static int sb1_dgpu_sw_remove(struct platform_device *pdev) ++{ ++ sysfs_remove_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); ++ return 0; ++} ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .probe = sb1_dgpu_sw_probe, ++ .remove = sb1_dgpu_sw_remove, ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.45.2 + diff --git a/patches/6.10/0009-surface-button.patch b/patches/6.10/0009-surface-button.patch new file mode 100644 index 0000000000..bdee9d5d38 --- /dev/null +++ b/patches/6.10/0009-surface-button.patch @@ -0,0 +1,149 @@ +From 1afbbb29ce7bd15bbf4f812cbc034514bb667b43 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index f6d060377d18..b8603f74eb28 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.45.2 + +From 888fc8298e984f1cb23ac66e91a02d2e7f174919 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.45.2 + diff --git a/patches/6.10/0010-surface-typecover.patch b/patches/6.10/0010-surface-typecover.patch new file mode 100644 index 0000000000..7e4bd42344 --- /dev/null +++ b/patches/6.10/0010-surface-typecover.patch @@ -0,0 +1,573 @@ +From 201768f64dd2128028bed46940ecd9ea85483973 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 13171454f959..a83beefd25f3 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.45.2 + +From 9ae353f19e719e680d93710ec61aef6edefab6f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 56fc78841f24..a266449065a0 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -34,7 +34,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -168,6 +175,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + + #define MT_DEFAULT_MAXCONTACT 10 + #define MT_MAX_MAXCONTACT 250 +@@ -396,6 +406,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_SEPARATE_APP_REPORT, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1720,6 +1740,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1743,6 +1826,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1781,15 +1867,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1839,6 +1929,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2235,6 +2326,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.45.2 + +From 922102cc310758a2655f9bb3eb9a413bc551b1a7 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index a266449065a0..060c706e936a 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -408,6 +411,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1389,6 +1393,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1416,6 +1423,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1437,6 +1459,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1444,6 +1467,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1453,11 +1489,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1610,6 +1656,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1658,6 +1740,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1740,30 +1829,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1772,8 +1837,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1907,13 +1973,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1922,12 +1999,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.45.2 + diff --git a/patches/6.10/0011-surface-shutdown.patch b/patches/6.10/0011-surface-shutdown.patch new file mode 100644 index 0000000000..474d3a7678 --- /dev/null +++ b/patches/6.10/0011-surface-shutdown.patch @@ -0,0 +1,97 @@ +From dc75889e49675c868d33320a996c33d183fee94a Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index af2996d0d17f..3ce0fb61257d 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 568410e64ce6..f59d8fb36335 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6273,3 +6273,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index cafc5ab1cbcb..64bb5aca2c13 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -465,6 +465,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.45.2 + diff --git a/patches/6.10/0012-surface-gpe.patch b/patches/6.10/0012-surface-gpe.patch new file mode 100644 index 0000000000..05421ea250 --- /dev/null +++ b/patches/6.10/0012-surface-gpe.patch @@ -0,0 +1,51 @@ +From 41732ed4458eb3b08b4a658f1cd617d83c90cec6 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index 62fd4004db31..103fc4468262 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.45.2 + diff --git a/patches/6.10/0013-cameras.patch b/patches/6.10/0013-cameras.patch new file mode 100644 index 0000000000..d1e0478bc1 --- /dev/null +++ b/patches/6.10/0013-cameras.patch @@ -0,0 +1,780 @@ +From 2d145df171e42d90ac54b0bdc42e77337e99679a Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 503773707e01..a292a20c4315 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2176,6 +2176,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.45.2 + +From f0e749b5b8f19dca95eaf7b24c925f7684669993 Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 8d95579436a9..cbfb59ed5985 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -45,6 +45,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -223,12 +230,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -2203,6 +2212,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2505,6 +2517,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4630,6 +4645,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4677,6 +4704,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.45.2 + +From 197059f84ca0575efb65a4667023e9e14c53fe87 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 1e107fd49f82..e3e1696e7f0e 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.45.2 + +From cff4d571011727ee47c29f21c9b1d255ca4efe8e Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 07b302e09340..1d3097bc7e48 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity = GPIO_ACTIVE_HIGH; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) +-- +2.45.2 + +From 31cab2b99a833eab39602f61e3f3f801884f8980 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.45.2 + +From b17d182f347660c7c2e873d0a2e21b57ce44858c Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index c477723c07bf..83413048eb35 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -795,6 +795,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index 89c7192148df..44eca113e772 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.45.2 + +From c51c33aa1cdbea15c1b493b300f66408d8306bd9 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index e3e1696e7f0e..423dc555093f 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.45.2 + +From b37b24f5e18fd586452ec4a7cc978c3360074e42 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.45.2 + +From 8ef5b1010e49d11964f2dd7da3c3271f5f9bf503 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 05e6af88b88c..c120eb0b5aa8 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -909,6 +909,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index effdfc6f1e95..6ce609b2cdac 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -86,6 +86,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.45.2 + +From ca688e057ec8149ccd01d2c7876b707aa33bdbc8 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Sat, 3 Feb 2024 12:59:53 +0900 +Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on + stream stop + +Adapt to 009905e "media: v4l2-subdev: Document and enforce .s_stream() requirements" + +Patchset: cameras +--- + drivers/staging/media/ipu3/ipu3-v4l2.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c +index 3df58eb3e882..81aff2d5d898 100644 +--- a/drivers/staging/media/ipu3/ipu3-v4l2.c ++++ b/drivers/staging/media/ipu3/ipu3-v4l2.c +@@ -538,18 +538,18 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq) + + WARN_ON(!node->enabled); + +- pipe = node->pipe; +- dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); +- imgu_pipe = &imgu->imgu_pipe[pipe]; +- r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); +- if (r) +- dev_err(&imgu->pci_dev->dev, +- "failed to stop subdev streaming\n"); +- + mutex_lock(&imgu->streaming_lock); + /* Was this the first node with streaming disabled? */ + if (imgu->streaming && imgu_all_nodes_streaming(imgu, node)) { + /* Yes, really stop streaming now */ ++ pipe = node->pipe; ++ dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); ++ imgu_pipe = &imgu->imgu_pipe[pipe]; ++ r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); ++ if (r) ++ dev_err(&imgu->pci_dev->dev, ++ "failed to stop subdev streaming\n"); ++ + dev_dbg(dev, "IMGU streaming is ready to stop"); + r = imgu_s_stream(imgu, false); + if (!r) +-- +2.45.2 + +From d267b727836905eaefc1541eb743479338827db5 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.45.2 + diff --git a/patches/6.10/0014-amd-gpio.patch b/patches/6.10/0014-amd-gpio.patch new file mode 100644 index 0000000000..9c83716985 --- /dev/null +++ b/patches/6.10/0014-amd-gpio.patch @@ -0,0 +1,109 @@ +From 68bfb06084548d1f7d23fc2c5e7c4b70262078b3 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 4bf82dbd2a6b..7a8cb090c656 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1216,6 +1217,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1271,6 +1283,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.45.2 + +From f72f4d6bc2d6e1f1ec68422cffaed5e77820c6c5 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 7a8cb090c656..0faafc323e67 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1219,12 +1219,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.45.2 + diff --git a/patches/6.10/0015-rtc.patch b/patches/6.10/0015-rtc.patch new file mode 100644 index 0000000000..e8ab243e84 --- /dev/null +++ b/patches/6.10/0015-rtc.patch @@ -0,0 +1,110 @@ +From ca8843e551ab3528c958bc8efaa51356dbdc23de Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 1d670dbe4d1d..71c9e375ca1c 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -432,6 +432,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -480,15 +488,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -564,13 +571,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -612,12 +624,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -648,6 +654,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.45.2 + From 6445fb63de1c957ef5fb8b93d53bb8a7a556c4ab Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Aug 2024 16:50:57 +0200 Subject: [PATCH 043/236] Update Arch kernel to v6.10.3 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3-oemb.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- pkg/arch/kernel/0007-surface-sam.patch | 2 +- .../kernel/0008-surface-sam-over-hid.patch | 2 +- pkg/arch/kernel/0009-surface-button.patch | 2 +- pkg/arch/kernel/0010-surface-typecover.patch | 2 +- pkg/arch/kernel/0011-surface-shutdown.patch | 2 +- pkg/arch/kernel/0012-surface-gpe.patch | 2 +- pkg/arch/kernel/0013-cameras.patch | 2 +- pkg/arch/kernel/0014-amd-gpio.patch | 2 +- pkg/arch/kernel/0015-rtc.patch | 2 +- pkg/arch/kernel/PKGBUILD | 34 +++++++++---------- pkg/arch/kernel/surface.config | 2 +- 17 files changed, 33 insertions(+), 33 deletions(-) diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 6c629b469a..53f1acf38e 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.9/0001-secureboot.patch \ No newline at end of file +../../../patches/6.10/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3-oemb.patch b/pkg/arch/kernel/0002-surface3-oemb.patch index 814b883e96..2ed0bb77ab 120000 --- a/pkg/arch/kernel/0002-surface3-oemb.patch +++ b/pkg/arch/kernel/0002-surface3-oemb.patch @@ -1 +1 @@ -../../../patches/6.9/0002-surface3-oemb.patch \ No newline at end of file +../../../patches/6.10/0002-surface3-oemb.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index d3663c2d95..0e93cc78bd 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.9/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.10/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index 95bd5d4622..516b0a84f6 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.9/0004-ath10k.patch \ No newline at end of file +../../../patches/6.10/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index 624485db20..006d633b22 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.9/0005-ipts.patch \ No newline at end of file +../../../patches/6.10/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index 6c0b1f09d9..9f19173f77 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.9/0006-ithc.patch \ No newline at end of file +../../../patches/6.10/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch index e9fa7179ce..bfb3707e2c 120000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -1 +1 @@ -../../../patches/6.9/0007-surface-sam.patch \ No newline at end of file +../../../patches/6.10/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch index cc03a209dd..6a39f547a4 120000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -1 +1 @@ -../../../patches/6.9/0008-surface-sam-over-hid.patch \ No newline at end of file +../../../patches/6.10/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch index a2f074fffc..00ff866efe 120000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -1 +1 @@ -../../../patches/6.9/0009-surface-button.patch \ No newline at end of file +../../../patches/6.10/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch index e068d3c47f..b432019d84 120000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -1 +1 @@ -../../../patches/6.9/0010-surface-typecover.patch \ No newline at end of file +../../../patches/6.10/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch index 284553d689..21677cc427 120000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -1 +1 @@ -../../../patches/6.9/0011-surface-shutdown.patch \ No newline at end of file +../../../patches/6.10/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch index 6d1f1de95b..0186089384 120000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -1 +1 @@ -../../../patches/6.9/0012-surface-gpe.patch \ No newline at end of file +../../../patches/6.10/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch index 6657233011..0b99c35459 120000 --- a/pkg/arch/kernel/0013-cameras.patch +++ b/pkg/arch/kernel/0013-cameras.patch @@ -1 +1 @@ -../../../patches/6.9/0013-cameras.patch \ No newline at end of file +../../../patches/6.10/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch index 4670c4612c..0be91a74dd 120000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -1 +1 @@ -../../../patches/6.9/0014-amd-gpio.patch \ No newline at end of file +../../../patches/6.10/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch index 45dfc813e5..94917a872d 120000 --- a/pkg/arch/kernel/0015-rtc.patch +++ b/pkg/arch/kernel/0015-rtc.patch @@ -1 +1 @@ -../../../patches/6.9/0015-rtc.patch \ No newline at end of file +../../../patches/6.10/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 201d9825f1..4312bd77ad 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.9.9.arch1 +pkgver=6.10.3.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('e26e4c0910dda677fd49acf9b48d20b5898f47d37e03644dbbaa01521c7c0ceb' +sha256sums=('60e9e52ee2353c533f02d91f952809289095d890cf09213af82a1baf4366ac90' '3acffee6493e810bd13f042b0a8e97e2b66a977b8ae7ec7c25a604446271860f' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - 'f14d2f34cc9474a130afd2241eaece2890f18970babcebc73da644a5bfcdbc6f' - '4590d2e70aeff57e5826ec78129d3c64204c7e14cbca675466d049874df77409' - '9534a110b47431f303bef18fcccd442c3c75ca4fedb826b03ebe2512396ae364' - 'd26a9d1737a86fc1c83b43761b18549d504640283a702679ae7450e16a39f5e0' - '5febaed6a68544b6611efa60b9d40888704f08e23f7be48511f305aaac91d085' - 'c4786b657649fb5b4ff26e97663993b13a383191db8cfe577ec97efea4762ad9' - 'eeab31d3906b3d37691bfa075b32e46c5bbfdfa5d36d3846c89631ad90f6791a' - '0b0fbc8e355a4bcd6470bf450c12f76bb9e84148aa2d871beb28479371e23744' - '38cb53cccda06fada526b26b44ef8b27c6043bafc2fcc2b1a8a828b330badf99' - 'e1f9ea6860ddf9980c67c48800dd2833d818d07e4c50ae6ab194af3016a3e037' - '462813550b2be2c0868a9d2901fbcc78057854ee291ca9287bfa4af6da7972af' - '129dee890fe9c31384c9b2b8c83c3849829c54ed4212c5b543e9f551ecf3cedc' - '6ebec733af1d893fb613bc5e53c885af688d099eb87cc75425b8f2991aad9f77' - '6db4054dc5859ee892fa657948d6e0fe29a813b35d2e7e4fdb45ed85e57a8875' - '2e178ce02502cb8de433f46d1efaf5f24fec1bf34185bd104d63e50c1d916609') + '1b70858dc5ba00d346163d0b24a13914b1a4b3433d6543aeac58d1c8bb6e8341' + 'fbac5d2845ea266b7665a1d30c5f4dd7bc9e9d062910776b8236c6b89d4761b9' + '8200e0d8671e294a37f4502b2446fed007b99b1792f4afcbc79dc528061ff1a4' + '5663c162b6f1593a93ad96c7f076bc86e028e0a3c4fd44bcc5c1c0ada0aa2981' + 'a8908f723fccccf807e80a5a0d23f923f7c153643a2fb103c01e902aaddb55b2' + '203e8e16d56b335d712ac5144bc70bdc996cb8910746d3624430a73fa3535669' + '204adce6eb3ef3c36c9c4392f226b49dd308aa23a3ebeed6ac367f982b1c5360' + '118cc0d87e8924d7c2ab04c7bb3973715b90b60b10705d9d69c84f7b517695fb' + '16ad802460b20ce95a56f8cdfaf51fb94be2a7b827cdb33c1c0e9a5590d61adc' + '937acd6d4ac0d7154572d99154b79a984b3f16c98f6fff7c896f3651b568c6c4' + 'dc40bf967e697bb2b9945a3e4f7c53cd5477e1b7bffb7de2fcad0219bec1a11d' + '45f3c48158093487b9e6cf3e68286d31a930eb5bc288b3261d7b17d7f1d0f066' + '9830746d86d510d0efcab9b7c34a4ea6923cb0c4e145188b726af73ae6acfe20' + '45a2b649e3fe74c3a05335c2074433e30f35d86a440e655beef15878252965c3' + '304e67dad6628bd7ee13666f4c95a3ee980d1a222f0451bae24d40d681f16061') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index f20c155d2a..334f7098f2 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.9.config \ No newline at end of file +../../../configs/surface-6.10.config \ No newline at end of file From f189b1b4d1cef7baa29fa74a626f776e04c5fecc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Aug 2024 16:52:08 +0200 Subject: [PATCH 044/236] Update Debian kernel to v6.10.3 --- ...01-Add-secureboot-pre-signing-to-the-kernel.patch | 12 ++++++------ ...-revert-integrity-Only-use-machine-keyring-.patch | 6 +++--- .../0001-kbuild-Link-sign-file-statically.patch | 6 +++--- pkg/debian/kernel/version.conf | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch index 51deb180c9..2b4b9c8266 100644 --- a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch +++ b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch @@ -1,4 +1,4 @@ -From 43a7e8759162fa25aea203ce732f177bc6f15cdb Mon Sep 17 00:00:00 2001 +From e4eb5bb44e5ac84958c641f62fcfec5114d03073 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 22 Sep 2019 22:44:16 +0200 Subject: [PATCH] Add secureboot pre-signing to the kernel @@ -21,10 +21,10 @@ Signed-off-by: Dorian Stoll create mode 100755 scripts/sign_kernel.sh diff --git a/.gitignore b/.gitignore -index 7f86e0837909..04aaae490610 100644 +index c59dc60ba62e..d60f75150ebf 100644 --- a/.gitignore +++ b/.gitignore -@@ -152,6 +152,9 @@ signing_key.priv +@@ -149,6 +149,9 @@ signing_key.priv signing_key.x509 x509.genkey @@ -35,10 +35,10 @@ index 7f86e0837909..04aaae490610 100644 /all.config /alldef.config diff --git a/arch/x86/Makefile b/arch/x86/Makefile -index fdc2e3abd615..c7a374c7ceaf 100644 +index 801fd85c3ef6..1b1a72179a74 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile -@@ -283,6 +283,7 @@ endif +@@ -302,6 +302,7 @@ endif $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE) $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@ @@ -83,5 +83,5 @@ index 000000000000..d2526a279254 +sbsign --key $BUILDDIR/keys/MOK.key --cert $BUILDDIR/keys/MOK.crt \ + --output $VMLINUX $VMLINUX -- -2.41.0 +2.45.2 diff --git a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch index f80dc33031..c13278103c 100644 --- a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch +++ b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch @@ -1,4 +1,4 @@ -From fbfaff58fe821fa93ceeb17e034886a6d8447207 Mon Sep 17 00:00:00 2001 +From 556d277d8397c8bd0c5889a309e50290d491e41c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 22:54:05 +0100 Subject: [PATCH] Partially revert "integrity: Only use machine keyring when @@ -17,7 +17,7 @@ loading. Therefore, revert this change. 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/security/integrity/platform_certs/machine_keyring.c b/security/integrity/platform_certs/machine_keyring.c -index a401640a63cd1..a1ad244cbf86d 100644 +index a401640a63cd..a1ad244cbf86 100644 --- a/security/integrity/platform_certs/machine_keyring.c +++ b/security/integrity/platform_certs/machine_keyring.c @@ -51,14 +51,7 @@ void __init add_to_machine_keyring(const char *source, const void *data, size_t @@ -37,5 +37,5 @@ index a401640a63cd1..a1ad244cbf86d 100644 static bool __init trust_moklist(void) -- -2.42.1 +2.45.2 diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index 7c79eee9b1..7104412d3c 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -1,4 +1,4 @@ -From 4113f0e722d93a3728d18464a88d752939e37d9d Mon Sep 17 00:00:00 2001 +From 71701f82718799df961b252fef44e2a75f31e408 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:10:28 +0200 Subject: [PATCH] kbuild: Link sign-file statically @@ -8,7 +8,7 @@ Subject: [PATCH] kbuild: Link sign-file statically 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile b/scripts/Makefile -index bc90520a54266..1d092bfd28e3a 100644 +index fe56eeef09dd..e614f49b17e5 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -29,7 +29,7 @@ HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include @@ -21,5 +21,5 @@ index bc90520a54266..1d092bfd28e3a 100644 ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) -- -2.45.1 +2.45.2 diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index ce3f537e3c..a6cc9bfc7b 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.9.9" +KERNEL_VERSION="6.10.3" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From c0e613bcfbb32f102a3b5819e54edb378659d806 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Aug 2024 16:55:55 +0200 Subject: [PATCH 045/236] Update Fedora kernels to v6.9.12 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 4525cdc90e..7bb17c099f 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.9.9-0" +PACKAGE_TAG = "kernel-6.9.12-0" ## ## The release number of the modified kernel package. From 4439a5efb6516c443df5f52173cb55aef01560d1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 16 Aug 2024 12:27:30 +0200 Subject: [PATCH 046/236] pkg/debian: Disable GDS mitigations to prevent invalid opcode issues GDS mitigations disable the AVX instruction set if patched microcode is not present. Unfortunately, some programs depend on AVX (and do not check AVX presence), which leads to opcode errors if GDS mitigation is enabled. So disable it for now. --- pkg/debian/kernel/ubuntu.config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/debian/kernel/ubuntu.config b/pkg/debian/kernel/ubuntu.config index a8577bec08..64ad8192a9 100644 --- a/pkg/debian/kernel/ubuntu.config +++ b/pkg/debian/kernel/ubuntu.config @@ -64,6 +64,14 @@ CONFIG_ACPI_I2C_OPREGION=y # CONFIG_VIDEO_ATOMISP_OV5693 is not set +## +## Disable GDS mitigation. Enabling GDS mitigations disables AVX +## instructions, which causes a bunch of invalid opcode errors because +## some programs assume AVX is present. +## + +# CONFIG_MITIGATION_GDS_FORCE is not set + ## ## Disable evbug. It's annoying and potentially even a security risk when ## posting kernel logs... From 497f0cd48c4d78f5c67544099207d64c79d16ee1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 17 Aug 2024 03:25:05 +0200 Subject: [PATCH 047/236] Update v6.10 patches Changes: - Rebase onto v6.10.3 Links: - kernel: https://github.com/linux-surface/kernel/commit/17c8b97354ad07e4f34308b0bb72792245bf50d8 --- patches/6.10/0001-secureboot.patch | 4 +- patches/6.10/0002-surface3-oemb.patch | 4 +- patches/6.10/0003-mwifiex.patch | 12 +++--- patches/6.10/0004-ath10k.patch | 4 +- patches/6.10/0005-ipts.patch | 12 +++--- patches/6.10/0006-ithc.patch | 8 ++-- patches/6.10/0007-surface-sam.patch | 36 ++++++++-------- patches/6.10/0008-surface-sam-over-hid.patch | 8 ++-- patches/6.10/0009-surface-button.patch | 8 ++-- patches/6.10/0010-surface-typecover.patch | 12 +++--- patches/6.10/0011-surface-shutdown.patch | 4 +- patches/6.10/0012-surface-gpe.patch | 4 +- patches/6.10/0013-cameras.patch | 44 ++++++++++---------- patches/6.10/0014-amd-gpio.patch | 8 ++-- patches/6.10/0015-rtc.patch | 4 +- 15 files changed, 86 insertions(+), 86 deletions(-) diff --git a/patches/6.10/0001-secureboot.patch b/patches/6.10/0001-secureboot.patch index c3ee33d860..f1dc041286 100644 --- a/patches/6.10/0001-secureboot.patch +++ b/patches/6.10/0001-secureboot.patch @@ -1,4 +1,4 @@ -From fa4500c4ae1546dba5d5e4fbada8e6d0406adab0 Mon Sep 17 00:00:00 2001 +From 252c5b2e65865a2a3aa6a5400f204c47d22490ee Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,5 +33,5 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0002-surface3-oemb.patch b/patches/6.10/0002-surface3-oemb.patch index ef149645aa..82db24aca0 100644 --- a/patches/6.10/0002-surface3-oemb.patch +++ b/patches/6.10/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From b161e7d8c1f16ef72ed5195aa97e6357e06bdc4e Mon Sep 17 00:00:00 2001 +From 1146270e92aee0b612dfe695bcf8f7131a19bcf3 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,5 +97,5 @@ index 5e2ec60e2954..207868c699f2 100644 }; -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0003-mwifiex.patch b/patches/6.10/0003-mwifiex.patch index 6c38a11244..8e214c3fd8 100644 --- a/patches/6.10/0003-mwifiex.patch +++ b/patches/6.10/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 2497b1ba9fa349ddf764c38c46160a785a5f3475 Mon Sep 17 00:00:00 2001 +From 800e9cfe84a3eadd4dc9ae700940068e77fa8a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.45.2 +2.46.0 -From 52c3a74193a1e37e241dc8a8cef0a71e843a29b5 Mon Sep 17 00:00:00 2001 +From d51c5a356fee57c99a8d181825f8f941f34749d7 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.45.2 +2.46.0 -From 338d5143d47a9de3d5a25f1fa203f6b6a95864ef Mon Sep 17 00:00:00 2001 +From 317cde3654592dcb3e072d0d2fe7b4e5598cc078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -396,5 +396,5 @@ index 789c492df6fa..1e766b6c1f9a 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0004-ath10k.patch b/patches/6.10/0004-ath10k.patch index 64d1e6abf9..886f510947 100644 --- a/patches/6.10/0004-ath10k.patch +++ b/patches/6.10/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 5030f889081c8676ae652623ad86b797b05d7221 Mon Sep 17 00:00:00 2001 +From 268a79fb66862ef22294397a425fd074fc336c34 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index bdf0552cd1c3..e062cc687689 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0005-ipts.patch b/patches/6.10/0005-ipts.patch index 78f53c16ca..31144224c2 100644 --- a/patches/6.10/0005-ipts.patch +++ b/patches/6.10/0005-ipts.patch @@ -1,4 +1,4 @@ -From 318ef833ea6bf3a2ef7566bad79931b216bd7423 Mon Sep 17 00:00:00 2001 +From 9904c59dbdd422b811974893bab69fc5b4bc9a03 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -35,9 +35,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.45.2 +2.46.0 -From ddcd34d797494f38ba7be0d9e46a919fda557576 Mon Sep 17 00:00:00 2001 +From b0d9ceae2f95a4e4093b07580bedc10821374555 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -142,9 +142,9 @@ index f55ec1fd7942..8d95579436a9 100644 { if (risky_device(dev)) -- -2.45.2 +2.46.0 -From 6ff2cce19a707fb565e9aebf9fb2b00fe845a46a Mon Sep 17 00:00:00 2001 +From ee1ebc3f9ec7a8418f418902817b5c5f4b51c21d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3237,5 +3237,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0006-ithc.patch b/patches/6.10/0006-ithc.patch index cf713b3f76..3a28a55bfd 100644 --- a/patches/6.10/0006-ithc.patch +++ b/patches/6.10/0006-ithc.patch @@ -1,4 +1,4 @@ -From 52e90ab224f06fd648ca85cd43a91670a9a4e683 Mon Sep 17 00:00:00 2001 +From 0d0e07366b425e953d6dab698d62dbe9a7546994 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index e4a70886678c..961a33b87c24 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.45.2 +2.46.0 -From a5da515376d209ea8610fed94888f48d9b64387f Mon Sep 17 00:00:00 2001 +From 19a947aa5cc417bd43656cf9d8bf010abdc6bc3f Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -2767,5 +2767,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0007-surface-sam.patch b/patches/6.10/0007-surface-sam.patch index 11283a69a8..7eae09105a 100644 --- a/patches/6.10/0007-surface-sam.patch +++ b/patches/6.10/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 5180e4810b868e0d3da85577b776a929cecf1d65 Mon Sep 17 00:00:00 2001 +From 17af44bcfe971e7b9dddad3735fad70bbda3fbf9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 19 Apr 2024 20:41:47 +0200 Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is @@ -51,9 +51,9 @@ index 7fc602e01487..7e89f547999b 100644 /* * Note: New events could still have been received after the previous -- -2.45.2 +2.46.0 -From 144dbc865c07df0290009d509b31635aac53a907 Mon Sep 17 00:00:00 2001 +From 00b833401e8060eb50db269e0681383454a74848 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Oct 2023 14:57:11 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -84,9 +84,9 @@ index 1c4d74db08c9..f826489dc69d 100644 { "MSHW0123", (unsigned long)ssam_node_group_sls }, -- -2.45.2 +2.46.0 -From 7b906ae84a56322a5098c77a774f5fb00b4318a5 Mon Sep 17 00:00:00 2001 +From 9e13165394bf1898d05c7d5a4a5adb1767d2307e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 19:47:00 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -154,9 +154,9 @@ index f826489dc69d..ef59a7b66667 100644 { }, }; -- -2.45.2 +2.46.0 -From d602c3714f0cc654b90de7800f844d6201eaa66b Mon Sep 17 00:00:00 2001 +From 83719d2cd70ad6ac1df993782e757ded15e881cc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 20:05:57 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -211,9 +211,9 @@ index ef59a7b66667..70a2ea5a1957 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.45.2 +2.46.0 -From 4bde7be038c7dced1b596c7d41e6f0bb3043d301 Mon Sep 17 00:00:00 2001 +From c188646846cc6e9db1134eb62208d088ce615312 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -439,9 +439,9 @@ index 000000000000..48c3e826713f +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.45.2 +2.46.0 -From ae82a35c632785771ebe2ad7f48006a1eb8f6a91 Mon Sep 17 00:00:00 2001 +From 31d334453ebc65b7868bf33b1963553586e64fa3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -634,9 +634,9 @@ index 48c3e826713f..4c08926139db 100644 "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, NULL); -- -2.45.2 +2.46.0 -From 6a80e0b93ce1d8cf9d1b7e383b4b951fb4908294 Mon Sep 17 00:00:00 2001 +From 36174000616d130e9b4655d69eb3bd5b07adbecb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:47:47 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -663,9 +663,9 @@ index 70a2ea5a1957..6b568804f70b 100644 &ssam_node_hid_main_touchpad, &ssam_node_hid_main_iid5, -- -2.45.2 +2.46.0 -From 3175ecd829a778ffef35956d8785877bb76fe4b0 Mon Sep 17 00:00:00 2001 +From e32f317be4ad620fb6683b62ad9e883f37e17f57 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:48:02 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -692,9 +692,9 @@ index 6b568804f70b..9046df95c043 100644 &ssam_node_hid_sam_keyboard, &ssam_node_hid_sam_penstash, -- -2.45.2 +2.46.0 -From aeef49471d7ec17f243c685b85c0c870c99e9e3d Mon Sep 17 00:00:00 2001 +From ebf64f6dcf1bdf0dbe80b5ec5e3d4b8a6cfab41e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 28 Jun 2024 22:31:37 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Support for @@ -746,5 +746,5 @@ index 9046df95c043..058f4edd8b66 100644 { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0008-surface-sam-over-hid.patch b/patches/6.10/0008-surface-sam-over-hid.patch index 5359c72309..d07a2851fe 100644 --- a/patches/6.10/0008-surface-sam-over-hid.patch +++ b/patches/6.10/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 56def3328ab5c84c33a87c062448f1f97e545282 Mon Sep 17 00:00:00 2001 +From 8dac7a369f2f1c461750a3c3f6d93caae9566ace Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -108,9 +108,9 @@ index 14ae0cfc325e..a3a9f81fb47f 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.45.2 +2.46.0 -From 99ca5a4092ea27b42c256940694e13a8f2abd457 Mon Sep 17 00:00:00 2001 +From fe964119c511036a560d1dfcbec1196ae4ed1621 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -331,5 +331,5 @@ index 000000000000..8b816ed8f35c +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0009-surface-button.patch b/patches/6.10/0009-surface-button.patch index bdee9d5d38..34a615d252 100644 --- a/patches/6.10/0009-surface-button.patch +++ b/patches/6.10/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 1afbbb29ce7bd15bbf4f812cbc034514bb667b43 Mon Sep 17 00:00:00 2001 +From d811fb8e32e1327baf131c85522aee281f4281af Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index f6d060377d18..b8603f74eb28 100644 /* -- -2.45.2 +2.46.0 -From 888fc8298e984f1cb23ac66e91a02d2e7f174919 Mon Sep 17 00:00:00 2001 +From e21138766921f4a22e710b4858f75f98e308c61d Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0010-surface-typecover.patch b/patches/6.10/0010-surface-typecover.patch index 7e4bd42344..cad46568fa 100644 --- a/patches/6.10/0010-surface-typecover.patch +++ b/patches/6.10/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 201768f64dd2128028bed46940ecd9ea85483973 Mon Sep 17 00:00:00 2001 +From a19b7328ccb6c090354593fa039e5283140a5e69 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -37,9 +37,9 @@ index 13171454f959..a83beefd25f3 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.45.2 +2.46.0 -From 9ae353f19e719e680d93710ec61aef6edefab6f1 Mon Sep 17 00:00:00 2001 +From 99fb371b3a11e3c3d67d29673508911b81a1408c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -270,9 +270,9 @@ index 56fc78841f24..a266449065a0 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.45.2 +2.46.0 -From 922102cc310758a2655f9bb3eb9a413bc551b1a7 Mon Sep 17 00:00:00 2001 +From 7b797164a3f2ecf402b8f24d5123e74914b09064 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -569,5 +569,5 @@ index a266449065a0..060c706e936a 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0011-surface-shutdown.patch b/patches/6.10/0011-surface-shutdown.patch index 474d3a7678..87316e45a8 100644 --- a/patches/6.10/0011-surface-shutdown.patch +++ b/patches/6.10/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From dc75889e49675c868d33320a996c33d183fee94a Mon Sep 17 00:00:00 2001 +From e26e0570db9e2dbb37e075ef7a88270fe793fb94 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -93,5 +93,5 @@ index cafc5ab1cbcb..64bb5aca2c13 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0012-surface-gpe.patch b/patches/6.10/0012-surface-gpe.patch index 05421ea250..0dd835c3cc 100644 --- a/patches/6.10/0012-surface-gpe.patch +++ b/patches/6.10/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 41732ed4458eb3b08b4a658f1cd617d83c90cec6 Mon Sep 17 00:00:00 2001 +From bed56a2a67db8c5934008ed83fa0bbd71360ab02 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0013-cameras.patch b/patches/6.10/0013-cameras.patch index d1e0478bc1..9f36fc5c40 100644 --- a/patches/6.10/0013-cameras.patch +++ b/patches/6.10/0013-cameras.patch @@ -1,4 +1,4 @@ -From 2d145df171e42d90ac54b0bdc42e77337e99679a Mon Sep 17 00:00:00 2001 +From 0a70aafbfa7ad39054c0974e428935c9d9e48cf1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index 503773707e01..a292a20c4315 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.45.2 +2.46.0 -From f0e749b5b8f19dca95eaf7b24c925f7684669993 Mon Sep 17 00:00:00 2001 +From bdae5b6a0e462398fa6035a2f0de8efae144abe4 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -182,9 +182,9 @@ index 8d95579436a9..cbfb59ed5985 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.45.2 +2.46.0 -From 197059f84ca0575efb65a4667023e9e14c53fe87 Mon Sep 17 00:00:00 2001 +From aa044fab288ddf51ad963effe090d0b548d83243 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 1e107fd49f82..e3e1696e7f0e 100644 return 0; -- -2.45.2 +2.46.0 -From cff4d571011727ee47c29f21c9b1d255ca4efe8e Mon Sep 17 00:00:00 2001 +From 12da0a015e6d71071561668950a4fb5e33220af8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -274,9 +274,9 @@ index 07b302e09340..1d3097bc7e48 100644 agpio, func, polarity); if (ret) -- -2.45.2 +2.46.0 -From 31cab2b99a833eab39602f61e3f3f801884f8980 Mon Sep 17 00:00:00 2001 +From ddc65d1014592b1fe4d6e16c9badcc928e577b3b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -313,9 +313,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.45.2 +2.46.0 -From b17d182f347660c7c2e873d0a2e21b57ce44858c Mon Sep 17 00:00:00 2001 +From ea560c5a7e55695438ac99fbd363352991fe62af Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -364,9 +364,9 @@ index 89c7192148df..44eca113e772 100644 if (ret < 0) goto out_cleanup; -- -2.45.2 +2.46.0 -From c51c33aa1cdbea15c1b493b300f66408d8306bd9 Mon Sep 17 00:00:00 2001 +From 0c59f9eee1c8dc8ea4d99f8b1a07b342ef5e425d Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -405,9 +405,9 @@ index e3e1696e7f0e..423dc555093f 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.45.2 +2.46.0 -From b37b24f5e18fd586452ec4a7cc978c3360074e42 Mon Sep 17 00:00:00 2001 +From 8f69fe36b3d6052c7f41182041fc59ea84515066 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -446,9 +446,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.45.2 +2.46.0 -From 8ef5b1010e49d11964f2dd7da3c3271f5f9bf503 Mon Sep 17 00:00:00 2001 +From 457ccb4dad651a58bc24e4c49fcc95a81e3762bb Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -697,9 +697,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.45.2 +2.46.0 -From ca688e057ec8149ccd01d2c7876b707aa33bdbc8 Mon Sep 17 00:00:00 2001 +From 281dcaef04abcc6a75b34c6f69f8f608b68912cf Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -744,9 +744,9 @@ index 3df58eb3e882..81aff2d5d898 100644 r = imgu_s_stream(imgu, false); if (!r) -- -2.45.2 +2.46.0 -From d267b727836905eaefc1541eb743479338827db5 Mon Sep 17 00:00:00 2001 +From f1d09776b3c5026bfd4d035bbca5be3f8e41b247 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -776,5 +776,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0014-amd-gpio.patch b/patches/6.10/0014-amd-gpio.patch index 9c83716985..b1a3d0a01f 100644 --- a/patches/6.10/0014-amd-gpio.patch +++ b/patches/6.10/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 68bfb06084548d1f7d23fc2c5e7c4b70262078b3 Mon Sep 17 00:00:00 2001 +From 29121bd1e5b235572d56645abdb8f54a31bf476e Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 4bf82dbd2a6b..7a8cb090c656 100644 mp_config_acpi_legacy_irqs(); -- -2.45.2 +2.46.0 -From f72f4d6bc2d6e1f1ec68422cffaed5e77820c6c5 Mon Sep 17 00:00:00 2001 +From f8d58835a76ce8ea016c0fcd75ddb93a95ca14c6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 7a8cb090c656..0faafc323e67 100644 }; -- -2.45.2 +2.46.0 diff --git a/patches/6.10/0015-rtc.patch b/patches/6.10/0015-rtc.patch index e8ab243e84..78e2d0b991 100644 --- a/patches/6.10/0015-rtc.patch +++ b/patches/6.10/0015-rtc.patch @@ -1,4 +1,4 @@ -From ca8843e551ab3528c958bc8efaa51356dbdc23de Mon Sep 17 00:00:00 2001 +From 5c662b210790b2b297457de3e84274cc062b215e Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 1d670dbe4d1d..71c9e375ca1c 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.45.2 +2.46.0 From 3c74ab491a70b8e2a783cc96df4f2836483fc4d0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 17 Aug 2024 03:27:15 +0200 Subject: [PATCH 048/236] Update Arch kernel to v6.10.5 --- pkg/arch/kernel/PKGBUILD | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 4312bd77ad..40639825a7 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.10.3.arch1 +pkgver=6.10.5.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('60e9e52ee2353c533f02d91f952809289095d890cf09213af82a1baf4366ac90' +sha256sums=('985b89c2cfc91950562f29da121b1a38d9ae60afad2c29175f685067c8357408' '3acffee6493e810bd13f042b0a8e97e2b66a977b8ae7ec7c25a604446271860f' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '1b70858dc5ba00d346163d0b24a13914b1a4b3433d6543aeac58d1c8bb6e8341' - 'fbac5d2845ea266b7665a1d30c5f4dd7bc9e9d062910776b8236c6b89d4761b9' - '8200e0d8671e294a37f4502b2446fed007b99b1792f4afcbc79dc528061ff1a4' - '5663c162b6f1593a93ad96c7f076bc86e028e0a3c4fd44bcc5c1c0ada0aa2981' - 'a8908f723fccccf807e80a5a0d23f923f7c153643a2fb103c01e902aaddb55b2' - '203e8e16d56b335d712ac5144bc70bdc996cb8910746d3624430a73fa3535669' - '204adce6eb3ef3c36c9c4392f226b49dd308aa23a3ebeed6ac367f982b1c5360' - '118cc0d87e8924d7c2ab04c7bb3973715b90b60b10705d9d69c84f7b517695fb' - '16ad802460b20ce95a56f8cdfaf51fb94be2a7b827cdb33c1c0e9a5590d61adc' - '937acd6d4ac0d7154572d99154b79a984b3f16c98f6fff7c896f3651b568c6c4' - 'dc40bf967e697bb2b9945a3e4f7c53cd5477e1b7bffb7de2fcad0219bec1a11d' - '45f3c48158093487b9e6cf3e68286d31a930eb5bc288b3261d7b17d7f1d0f066' - '9830746d86d510d0efcab9b7c34a4ea6923cb0c4e145188b726af73ae6acfe20' - '45a2b649e3fe74c3a05335c2074433e30f35d86a440e655beef15878252965c3' - '304e67dad6628bd7ee13666f4c95a3ee980d1a222f0451bae24d40d681f16061') + '0c37af13f4e726b402ecdc134221c9622e158e6a04e466c90074101f044e5e0c' + '1c7a7bbfcf425575c76b02f06e23961a26ae3f948bf0cd44c99050fcc8ff091b' + '9586e84ba44bbc2f857e57e516f2a143f373e1346e4bb3902b2e800f703999c3' + 'fd032cd48c753ac0ce7d2569d846b2be8d6c2fe855123c8b81632a9466f349eb' + '99e93f1f941223d93997708205db90a09afcec9eb49535676e48d8d7961f42fa' + '496e6e88557cc353fe4a492e125bd14ca1234391052c75d024b20bcd0250edfb' + 'e03e0f0e4dc204cff1148a338646ecd560596f5e716c48a1bc9fa651839e59bc' + 'de44054877918c141c4cb365ce7054f06603fe32c2036141a16f0c618d032ad2' + 'bbc0f2ac46971de82c5870568eb3373fa9cc5ebb434a264ce6527ea4ae5beb05' + '0fbcb31344552dcc9a1c8036dabe6fb7de968c1ff8b8dc209cd9cd7ad06115fa' + 'bd87365738e35b866182db0380b1193abc55cc74b4682789d2449a6878a3d251' + 'be7601388ff83a32be59b9e00b14b69b9af78d4a11d5522b803482f3d2c3b5fc' + 'ac71b84c661ed5af8988d5ca85686cecf8797719bcf8787baff8753ea09faa79' + '49608d0a7096a3dfe7971ff99bd3746cdcd214ddb7b7d19b1fe97e3578f62bd2' + '9f90b7d26f23c66ac48fb012afb4703a5cdd652b6d1ca1c491ffdce7c89ebde0') export KBUILD_BUILD_HOST=archlinux From f02ae51550ffecdfff42ddf077dd2db55030d911 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 17 Aug 2024 03:29:30 +0200 Subject: [PATCH 049/236] Update Debian kernel to v6.10.5 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index a6cc9bfc7b..9d5a8014c3 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.10.3" +KERNEL_VERSION="6.10.5" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 5db541cd8802edfbe91c01925972bf44eb7798af Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 17 Aug 2024 03:31:18 +0200 Subject: [PATCH 050/236] Update Fedora kernels to v6.10.5 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 7bb17c099f..4fcce2d8c6 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.9.12-0" +PACKAGE_TAG = "kernel-6.10.5-0" ## ## The release number of the modified kernel package. From acde9fbc4917f3b473b99dcb9a70606eaf1e9f96 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 17 Aug 2024 03:42:00 +0200 Subject: [PATCH 051/236] pkg/arch: Update base kernel config --- pkg/arch/kernel/PKGBUILD | 2 +- pkg/arch/kernel/config | 124 +++++++++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 38 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 40639825a7..df19a6bfab 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -58,7 +58,7 @@ validpgpkeys=( 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) sha256sums=('985b89c2cfc91950562f29da121b1a38d9ae60afad2c29175f685067c8357408' - '3acffee6493e810bd13f042b0a8e97e2b66a977b8ae7ec7c25a604446271860f' + '09bc22332affedcdf96cfa7b4ff3dcf1d087d1bde818b9929f5ad1102bc4f775' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' '0c37af13f4e726b402ecdc134221c9622e158e6a04e466c90074101f044e5e0c' diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index 4872e236ba..4ad0c33a56 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,15 +1,15 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.9.3-arch1 Kernel Configuration +# Linux/x86 6.10.5-arch1 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="gcc (GCC) 14.1.1 20240522" +CONFIG_CC_VERSION_TEXT="gcc (GCC) 14.2.1 20240805" CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=140101 +CONFIG_GCC_VERSION=140201 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y -CONFIG_AS_VERSION=24200 +CONFIG_AS_VERSION=24300 CONFIG_LD_IS_BFD=y -CONFIG_LD_VERSION=24200 +CONFIG_LD_VERSION=24300 CONFIG_LLD_VERSION=0 CONFIG_CC_CAN_LINK=y CONFIG_CC_CAN_LINK_STATIC=y @@ -18,7 +18,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=126 +CONFIG_PAHOLE_VERSION=127 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -78,6 +78,7 @@ CONFIG_GENERIC_MSI_IRQ=y CONFIG_IRQ_MSI_IOMMU=y CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_GENERIC_IRQ_STAT_SNAPSHOT=y CONFIG_IRQ_FORCED_THREADING=y CONFIG_SPARSE_IRQ=y # CONFIG_GENERIC_IRQ_DEBUGFS is not set @@ -165,6 +166,7 @@ CONFIG_RCU_EXPERT=y CONFIG_TREE_SRCU=y CONFIG_TASKS_RCU_GENERIC=y # CONFIG_FORCE_TASKS_RCU is not set +CONFIG_NEED_TASKS_RCU=y CONFIG_TASKS_RCU=y # CONFIG_FORCE_TASKS_RUDE_RCU is not set CONFIG_TASKS_RUDE_RCU=y @@ -212,6 +214,7 @@ CONFIG_CC_NO_STRINGOP_OVERFLOW=y CONFIG_ARCH_SUPPORTS_INT128=y CONFIG_NUMA_BALANCING=y CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y +CONFIG_SLAB_OBJ_EXT=y CONFIG_CGROUPS=y CONFIG_PAGE_COUNTER=y # CONFIG_CGROUP_FAVOR_DYNMODS is not set @@ -281,7 +284,6 @@ CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_PCSPKR_PLATFORM=y -CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_FUTEX_PI=y CONFIG_EPOLL=y @@ -368,6 +370,7 @@ CONFIG_CC_HAS_SANE_STACKPROTECTOR=y # CONFIG_SMP=y CONFIG_X86_X2APIC=y +CONFIG_X86_POSTED_MSI=y CONFIG_X86_MPPARSE=y CONFIG_X86_CPU_RESCTRL=y CONFIG_X86_FRED=y @@ -547,6 +550,7 @@ CONFIG_HAVE_LIVEPATCH=y # end of Processor type and features CONFIG_CC_HAS_NAMED_AS=y +CONFIG_CC_HAS_NAMED_AS_FIXED_SANITIZERS=y CONFIG_USE_X86_SEG_SUPPORT=y CONFIG_CC_HAS_SLS=y CONFIG_CC_HAS_RETURN_THUNK=y @@ -644,6 +648,7 @@ CONFIG_ACPI_HOTPLUG_IOAPIC=y CONFIG_ACPI_SBS=m CONFIG_ACPI_HED=y CONFIG_ACPI_BGRT=y +CONFIG_ACPI_NHLT=y CONFIG_ACPI_NFIT=m # CONFIG_NFIT_SECURITY_DEBUG is not set CONFIG_ACPI_NUMA=y @@ -791,6 +796,8 @@ CONFIG_AS_SHA1_NI=y CONFIG_AS_SHA256_NI=y CONFIG_AS_TPAUSE=y CONFIG_AS_GFNI=y +CONFIG_AS_VAES=y +CONFIG_AS_VPCLMULQDQ=y CONFIG_AS_WRUSS=y CONFIG_ARCH_CONFIGURES_CPU_MITIGATIONS=y @@ -944,6 +951,7 @@ CONFIG_DYNAMIC_SIGFRAME=y CONFIG_HAVE_ARCH_NODE_DEV_GROUP=y CONFIG_ARCH_HAS_HW_PTE_YOUNG=y CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y +CONFIG_ARCH_HAS_KERNEL_FPU_SUPPORT=y # # GCOV-based kernel profiling @@ -963,7 +971,6 @@ CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y # end of General architecture-dependent options CONFIG_RT_MUTEXES=y -CONFIG_BASE_SMALL=0 CONFIG_MODULE_SIG_FORMAT=y CONFIG_MODULES=y CONFIG_MODULE_DEBUGFS=y @@ -1007,7 +1014,6 @@ CONFIG_BLK_DEV_INTEGRITY_T10=y CONFIG_BLK_DEV_WRITE_MOUNTED=y CONFIG_BLK_DEV_ZONED=y CONFIG_BLK_DEV_THROTTLING=y -CONFIG_BLK_DEV_THROTTLING_LOW=y CONFIG_BLK_WBT=y CONFIG_BLK_WBT_MQ=y CONFIG_BLK_CGROUP_IOLATENCY=y @@ -1015,7 +1021,6 @@ CONFIG_BLK_CGROUP_FC_APPID=y CONFIG_BLK_CGROUP_IOCOST=y CONFIG_BLK_CGROUP_IOPRIO=y CONFIG_BLK_DEBUG_FS=y -CONFIG_BLK_DEBUG_FS_ZONED=y CONFIG_BLK_SED_OPAL=y CONFIG_BLK_INLINE_ENCRYPTION=y CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y @@ -1136,7 +1141,7 @@ CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y CONFIG_SPARSEMEM_VMEMMAP=y CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP=y CONFIG_ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP=y -CONFIG_HAVE_FAST_GUP=y +CONFIG_HAVE_GUP_FAST=y CONFIG_NUMA_KEEP_MEMINFO=y CONFIG_MEMORY_ISOLATION=y CONFIG_EXCLUSIVE_SYSTEM_RAM=y @@ -1176,6 +1181,7 @@ CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y # CONFIG_TRANSPARENT_HUGEPAGE_NEVER is not set CONFIG_THP_SWAP=y CONFIG_READ_ONLY_THP_FOR_FS=y +CONFIG_PGTABLE_HAS_HUGE_LEAVES=y CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_USE_PERCPU_NUMA_NODE_ID=y @@ -1222,6 +1228,7 @@ CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y CONFIG_PER_VMA_LOCK=y CONFIG_LOCK_MM_AND_FIND_VMA=y CONFIG_IOMMU_MM_DATA=y +CONFIG_EXECMEM=y # # Data Access Monitoring @@ -1242,6 +1249,7 @@ CONFIG_NET_INGRESS=y CONFIG_NET_EGRESS=y CONFIG_NET_XGRESS=y CONFIG_NET_REDIRECT=y +CONFIG_SKB_DECRYPTED=y CONFIG_SKB_EXTENSIONS=y # @@ -1272,6 +1280,7 @@ CONFIG_NET_KEY_MIGRATE=y CONFIG_XFRM_ESPINTCP=y CONFIG_SMC=m CONFIG_SMC_DIAG=m +CONFIG_SMC_LO=y CONFIG_XDP_SOCKETS=y CONFIG_XDP_SOCKETS_DIAG=m CONFIG_NET_HANDSHAKE=y @@ -2068,6 +2077,7 @@ CONFIG_BT_MTKUART=m CONFIG_BT_HCIRSI=m CONFIG_BT_VIRTIO=m CONFIG_BT_NXPUART=m +CONFIG_BT_INTEL_PCIE=m # end of Bluetooth device drivers CONFIG_AF_RXRPC=m @@ -2181,6 +2191,7 @@ CONFIG_LWTUNNEL_BPF=y CONFIG_DST_CACHE=y CONFIG_GRO_CELLS=y CONFIG_SOCK_VALIDATE_XMIT=y +CONFIG_NET_IEEE8021Q_HELPERS=y CONFIG_NET_SELFTESTS=m CONFIG_NET_SOCK_MSG=y CONFIG_NET_DEVLINK=y @@ -3135,6 +3146,7 @@ CONFIG_VXLAN=m CONFIG_GENEVE=m CONFIG_BAREUDP=m CONFIG_GTP=m +CONFIG_PFCP=m CONFIG_AMT=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m @@ -3353,6 +3365,8 @@ CONFIG_NET_VENDOR_HUAWEI=y CONFIG_HINIC=m CONFIG_NET_VENDOR_I825XX=y CONFIG_NET_VENDOR_INTEL=y +CONFIG_LIBETH=m +CONFIG_LIBIE=m CONFIG_E100=m CONFIG_E1000=m CONFIG_E1000E=m @@ -3584,7 +3598,6 @@ CONFIG_FDDI=m CONFIG_DEFXX=m CONFIG_SKFP=m # CONFIG_HIPPI is not set -CONFIG_NET_SB1000=m CONFIG_PHYLINK=m CONFIG_PHYLIB=m CONFIG_SWPHY=y @@ -3595,6 +3608,7 @@ CONFIG_SFP=m # # MII PHY device drivers # +CONFIG_AIR_EN8811H_PHY=m CONFIG_AMD_PHY=m CONFIG_ADIN_PHY=m CONFIG_ADIN1100_PHY=m @@ -3655,6 +3669,8 @@ CONFIG_XILINX_GMII2RGMII=m CONFIG_MICREL_KS8995MA=m CONFIG_PSE_CONTROLLER=y CONFIG_PSE_REGULATOR=m +CONFIG_PSE_PD692X0=m +CONFIG_PSE_TPS23881=m CONFIG_CAN_DEV=m CONFIG_CAN_VCAN=m CONFIG_CAN_VXCAN=m @@ -3669,7 +3685,6 @@ CONFIG_CAN_C_CAN=m CONFIG_CAN_C_CAN_PLATFORM=m CONFIG_CAN_C_CAN_PCI=m CONFIG_CAN_CC770=m -# CONFIG_CAN_CC770_ISA is not set CONFIG_CAN_CC770_PLATFORM=m CONFIG_CAN_CTUCANFD=m CONFIG_CAN_CTUCANFD_PCI=m @@ -3689,7 +3704,6 @@ CONFIG_CAN_PEAK_PCI=m CONFIG_CAN_PEAK_PCIEC=y CONFIG_CAN_PEAK_PCMCIA=m CONFIG_CAN_PLX_PCI=m -# CONFIG_CAN_SJA1000_ISA is not set CONFIG_CAN_SJA1000_PLATFORM=m CONFIG_CAN_SOFTING=m CONFIG_CAN_SOFTING_CS=m @@ -3887,6 +3901,7 @@ CONFIG_ATH11K_DEBUGFS=y CONFIG_ATH11K_SPECTRAL=y CONFIG_ATH12K=m CONFIG_ATH12K_DEBUG=y +CONFIG_ATH12K_DEBUGFS=y CONFIG_ATH12K_TRACING=y CONFIG_WLAN_VENDOR_ATMEL=y CONFIG_AT76C50X_USB=m @@ -4078,6 +4093,7 @@ CONFIG_RTLWIFI_PCI=m CONFIG_RTLWIFI_USB=m CONFIG_RTLWIFI_DEBUG=y CONFIG_RTL8192C_COMMON=m +CONFIG_RTL8192D_COMMON=m CONFIG_RTL8723_COMMON=m CONFIG_RTLBTCOEXIST=m CONFIG_RTL8XXXU=m @@ -4089,6 +4105,8 @@ CONFIG_RTW88_SDIO=m CONFIG_RTW88_USB=m CONFIG_RTW88_8822B=m CONFIG_RTW88_8822C=m +CONFIG_RTW88_8723X=m +CONFIG_RTW88_8703B=m CONFIG_RTW88_8723D=m CONFIG_RTW88_8821C=m CONFIG_RTW88_8822BE=m @@ -4099,6 +4117,7 @@ CONFIG_RTW88_8822CS=m CONFIG_RTW88_8822CU=m CONFIG_RTW88_8723DE=m CONFIG_RTW88_8723DS=m +CONFIG_RTW88_8723CS=m CONFIG_RTW88_8723DU=m CONFIG_RTW88_8821CE=m CONFIG_RTW88_8821CS=m @@ -4112,10 +4131,12 @@ CONFIG_RTW89_8851B=m CONFIG_RTW89_8852A=m CONFIG_RTW89_8852B=m CONFIG_RTW89_8852C=m +CONFIG_RTW89_8922A=m CONFIG_RTW89_8851BE=m CONFIG_RTW89_8852AE=m CONFIG_RTW89_8852BE=m CONFIG_RTW89_8852CE=m +CONFIG_RTW89_8922AE=m CONFIG_RTW89_DEBUG=y CONFIG_RTW89_DEBUGMSG=y CONFIG_RTW89_DEBUGFS=y @@ -4610,10 +4631,9 @@ CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_JSM=m # CONFIG_SERIAL_LANTIQ is not set CONFIG_SERIAL_SCCNXP=m -CONFIG_SERIAL_SC16IS7XX_CORE=m CONFIG_SERIAL_SC16IS7XX=m -CONFIG_SERIAL_SC16IS7XX_I2C=y -CONFIG_SERIAL_SC16IS7XX_SPI=y +CONFIG_SERIAL_SC16IS7XX_I2C=m +CONFIG_SERIAL_SC16IS7XX_SPI=m CONFIG_SERIAL_ALTERA_JTAGUART=m CONFIG_SERIAL_ALTERA_UART=m CONFIG_SERIAL_ALTERA_UART_MAXPORTS=4 @@ -4677,6 +4697,7 @@ CONFIG_HPET=y # CONFIG_HPET_MMAP is not set CONFIG_HANGCHECK_TIMER=m CONFIG_TCG_TPM=y +CONFIG_TCG_TPM2_HMAC=y CONFIG_HW_RANDOM_TPM=y CONFIG_TCG_TIS_CORE=y CONFIG_TCG_TIS=y @@ -4745,6 +4766,7 @@ CONFIG_I2C_AMD756_S4882=m CONFIG_I2C_AMD8111=m CONFIG_I2C_AMD_MP2=m CONFIG_I2C_I801=m +CONFIG_I2C_I801_MUX=y CONFIG_I2C_ISCH=m CONFIG_I2C_ISMT=m CONFIG_I2C_PIIX4=m @@ -4757,6 +4779,7 @@ CONFIG_I2C_SIS630=m CONFIG_I2C_SIS96X=m CONFIG_I2C_VIA=m CONFIG_I2C_VIAPRO=m +CONFIG_I2C_ZHAOXIN=m # # ACPI drivers @@ -4964,6 +4987,7 @@ CONFIG_GPIO_CDEV=y CONFIG_GPIO_CDEV_V1=y CONFIG_GPIO_GENERIC=m CONFIG_GPIO_REGMAP=m +CONFIG_GPIO_SWNODE_UNDEFINED=y CONFIG_GPIO_MAX730X=m CONFIG_GPIO_IDIO_16=m @@ -4974,6 +4998,7 @@ CONFIG_GPIO_AMDPT=m CONFIG_GPIO_DWAPB=m CONFIG_GPIO_EXAR=m CONFIG_GPIO_GENERIC_PLATFORM=m +CONFIG_GPIO_GRANITERAPIDS=m CONFIG_GPIO_ICH=m CONFIG_GPIO_MB86S7X=m CONFIG_GPIO_MENZ127=m @@ -5276,6 +5301,7 @@ CONFIG_SENSORS_IT87=m CONFIG_SENSORS_JC42=m CONFIG_SENSORS_POWERZ=m CONFIG_SENSORS_POWR1220=m +CONFIG_SENSORS_LENOVO_EC=m CONFIG_SENSORS_LINEAGE=m CONFIG_SENSORS_LTC2945=m CONFIG_SENSORS_LTC2947=m @@ -5353,6 +5379,7 @@ CONFIG_SENSORS_PMBUS=m CONFIG_SENSORS_ACBEL_FSG032=m CONFIG_SENSORS_ADM1266=m CONFIG_SENSORS_ADM1275=m +CONFIG_SENSORS_ADP1050=m CONFIG_SENSORS_BEL_PFE=m CONFIG_SENSORS_BPA_RS600=m CONFIG_SENSORS_DELTA_AHE50DC_FAN=m @@ -5404,11 +5431,13 @@ CONFIG_SENSORS_TPS53679=m CONFIG_SENSORS_TPS546D24=m CONFIG_SENSORS_UCD9000=m CONFIG_SENSORS_UCD9200=m +CONFIG_SENSORS_XDP710=m CONFIG_SENSORS_XDPE152=m CONFIG_SENSORS_XDPE122=m CONFIG_SENSORS_XDPE122_REGULATOR=y CONFIG_SENSORS_ZL6100=m CONFIG_SENSORS_PT5161L=m +CONFIG_SENSORS_PWM_FAN=m CONFIG_SENSORS_SBTSI=m CONFIG_SENSORS_SBRMI=m CONFIG_SENSORS_SHT15=m @@ -5549,6 +5578,7 @@ CONFIG_DA9052_WATCHDOG=m CONFIG_DA9055_WATCHDOG=m CONFIG_DA9063_WATCHDOG=m CONFIG_DA9062_WATCHDOG=m +CONFIG_LENOVO_SE10_WDT=m CONFIG_MENF21BMC_WATCHDOG=m CONFIG_MENZ069_WATCHDOG=m CONFIG_WDAT_WDT=m @@ -6229,6 +6259,7 @@ CONFIG_DVB_BUDGET=m CONFIG_DVB_BUDGET_CI=m CONFIG_DVB_BUDGET_AV=m CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_VIDEO_INTEL_IPU6=m CONFIG_INTEL_VSC=m CONFIG_IPU_BRIDGE=m CONFIG_RADIO_ADAPTERS=m @@ -6791,12 +6822,12 @@ CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_FBDEV_OVERALLOC=100 CONFIG_DRM_LOAD_EDID_FIRMWARE=y CONFIG_DRM_DISPLAY_HELPER=m +CONFIG_DRM_DISPLAY_DP_AUX_CEC=y +CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV=y CONFIG_DRM_DISPLAY_DP_HELPER=y CONFIG_DRM_DISPLAY_DP_TUNNEL=y CONFIG_DRM_DISPLAY_HDCP_HELPER=y CONFIG_DRM_DISPLAY_HDMI_HELPER=y -CONFIG_DRM_DP_AUX_CHARDEV=y -CONFIG_DRM_DP_CEC=y CONFIG_DRM_TTM=m CONFIG_DRM_EXEC=m CONFIG_DRM_GPUVM=m @@ -6939,8 +6970,8 @@ CONFIG_DRM_SSD130X=m CONFIG_DRM_SSD130X_I2C=m CONFIG_DRM_SSD130X_SPI=m CONFIG_DRM_HYPERV=m -CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y CONFIG_DRM_PRIVACY_SCREEN=y +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y # # Frame buffer Devices @@ -7350,6 +7381,7 @@ CONFIG_SND_SOC_AMD_LEGACY_MACH=m CONFIG_SND_SOC_AMD_SOF_MACH=m CONFIG_SND_AMD_SOUNDWIRE_ACPI=m CONFIG_SND_SOC_AMD_RPL_ACP6x=m +CONFIG_SND_SOC_AMD_ACP63_TOPLEVEL=m CONFIG_SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE=m CONFIG_SND_SOC_AMD_SOUNDWIRE=m CONFIG_SND_SOC_AMD_PS=m @@ -7441,7 +7473,6 @@ CONFIG_SND_SOC_INTEL_SOF_MAXIM_COMMON=m CONFIG_SND_SOC_INTEL_SOF_REALTEK_COMMON=m CONFIG_SND_SOC_INTEL_SOF_CIRRUS_COMMON=m CONFIG_SND_SOC_INTEL_SOF_NUVOTON_COMMON=m -CONFIG_SND_SOC_INTEL_SOF_SSP_COMMON=m CONFIG_SND_SOC_INTEL_SOF_BOARD_HELPERS=m CONFIG_SND_SOC_INTEL_HASWELL_MACH=m CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH=m @@ -7462,7 +7493,6 @@ CONFIG_SND_SOC_INTEL_SKL_RT286_MACH=m CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH=m CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH=m CONFIG_SND_SOC_INTEL_DA7219_MAX98357A_GENERIC=m -CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON=m CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH=m CONFIG_SND_SOC_INTEL_BXT_RT298_MACH=m CONFIG_SND_SOC_INTEL_SOF_WM8804_MACH=m @@ -7534,6 +7564,7 @@ CONFIG_SND_SOC_SOF_METEORLAKE=m CONFIG_SND_SOC_SOF_INTEL_LNL=m CONFIG_SND_SOC_SOF_LUNARLAKE=m CONFIG_SND_SOC_SOF_HDA_COMMON=m +CONFIG_SND_SOC_SOF_HDA_GENERIC=m CONFIG_SND_SOC_SOF_HDA_MLINK=m CONFIG_SND_SOC_SOF_HDA_LINK=y CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC=y @@ -7655,7 +7686,6 @@ CONFIG_SND_SOC_HDAC_HDA=m CONFIG_SND_SOC_HDA=m CONFIG_SND_SOC_ICS43432=m CONFIG_SND_SOC_IDT821034=m -CONFIG_SND_SOC_INNO_RK3036=m CONFIG_SND_SOC_MAX98088=m CONFIG_SND_SOC_MAX98090=m CONFIG_SND_SOC_MAX98357A=m @@ -7691,8 +7721,8 @@ CONFIG_SND_SOC_PCM5102A=m CONFIG_SND_SOC_PCM512x=m CONFIG_SND_SOC_PCM512x_I2C=m CONFIG_SND_SOC_PCM512x_SPI=m +CONFIG_SND_SOC_PCM6240=m CONFIG_SND_SOC_PEB2466=m -CONFIG_SND_SOC_RK3328=m CONFIG_SND_SOC_RL6231=m CONFIG_SND_SOC_RL6347A=m CONFIG_SND_SOC_RT274=m @@ -7992,6 +8022,7 @@ CONFIG_HID_UDRAW_PS3=m CONFIG_HID_U2FZERO=m CONFIG_HID_WACOM=m CONFIG_HID_WIIMOTE=m +CONFIG_HID_WINWING=m CONFIG_HID_XINMO=m CONFIG_HID_ZEROPLUS=m CONFIG_ZEROPLUS_FF=y @@ -8073,7 +8104,7 @@ CONFIG_USB_MON=m # CONFIG_USB_C67X00_HCD=m CONFIG_USB_XHCI_HCD=y -# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_DBGCAP=y CONFIG_USB_XHCI_PCI=m CONFIG_USB_XHCI_PCI_RENESAS=m CONFIG_USB_XHCI_PLATFORM=m @@ -8629,7 +8660,6 @@ CONFIG_LEDS_TRIGGER_CAMERA=m CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_NETDEV=m CONFIG_LEDS_TRIGGER_PATTERN=m -CONFIG_LEDS_TRIGGER_AUDIO=m CONFIG_LEDS_TRIGGER_TTY=m # @@ -8783,6 +8813,7 @@ CONFIG_RTC_DRV_RC5T583=m CONFIG_RTC_DRV_S35390A=m CONFIG_RTC_DRV_FM3130=m CONFIG_RTC_DRV_RX8010=m +CONFIG_RTC_DRV_RX8111=m CONFIG_RTC_DRV_RX8581=m CONFIG_RTC_DRV_RX8025=m CONFIG_RTC_DRV_EM3027=m @@ -8926,7 +8957,6 @@ CONFIG_UIO_AEC=m CONFIG_UIO_SERCOS3=m CONFIG_UIO_PCI_GENERIC=m CONFIG_UIO_NETX=m -CONFIG_UIO_PRUSS=m CONFIG_UIO_MF624=m CONFIG_UIO_HV_GENERIC=m CONFIG_UIO_DFL=m @@ -8951,6 +8981,7 @@ CONFIG_VFIO_PCI_IGD=y CONFIG_MLX5_VFIO_PCI=m CONFIG_PDS_VFIO_PCI=m CONFIG_VIRTIO_VFIO_PCI=m +CONFIG_QAT_VFIO_PCI=m # end of VFIO support for PCI devices CONFIG_VFIO_MDEV=m @@ -8966,10 +8997,10 @@ CONFIG_SEV_GUEST=m CONFIG_TDX_GUEST_DRIVER=m CONFIG_VIRTIO_ANCHOR=y CONFIG_VIRTIO=y -CONFIG_VIRTIO_PCI_LIB=m -CONFIG_VIRTIO_PCI_LIB_LEGACY=m +CONFIG_VIRTIO_PCI_LIB=y +CONFIG_VIRTIO_PCI_LIB_LEGACY=y CONFIG_VIRTIO_MENU=y -CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_PCI_ADMIN_LEGACY=y CONFIG_VIRTIO_PCI_LEGACY=y CONFIG_VIRTIO_VDPA=m @@ -8980,6 +9011,7 @@ CONFIG_VIRTIO_INPUT=m CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y CONFIG_VIRTIO_DMA_SHARED_BUFFER=m +CONFIG_VIRTIO_DEBUG=y CONFIG_VDPA=m CONFIG_VDPA_SIM=m CONFIG_VDPA_SIM_NET=m @@ -9057,7 +9089,6 @@ CONFIG_XEN_VIRTIO=y # CONFIG_GREYBUS is not set # CONFIG_COMEDI is not set CONFIG_STAGING=y -CONFIG_PRISM2_USB=m CONFIG_RTLLIB=m CONFIG_RTLLIB_CRYPTO_CCMP=m CONFIG_RTLLIB_CRYPTO_TKIP=m @@ -9129,7 +9160,6 @@ CONFIG_MOST_NET=m CONFIG_MOST_VIDEO=m CONFIG_MOST_I2C=m CONFIG_KS7010=m -CONFIG_PI433=m CONFIG_FIELDBUS_DEV=m # CONFIG_VME_BUS is not set # CONFIG_GOLDFISH is not set @@ -9191,12 +9221,14 @@ CONFIG_NVIDIA_WMI_EC_BACKLIGHT=m CONFIG_XIAOMI_WMI=m CONFIG_GIGABYTE_WMI=m CONFIG_YOGABOOK=m +CONFIG_YT2_1380=m CONFIG_ACERHDF=m CONFIG_ACER_WIRELESS=m CONFIG_ACER_WMI=m CONFIG_AMD_PMF=m # CONFIG_AMD_PMF_DEBUG is not set CONFIG_AMD_PMC=m +CONFIG_AMD_MP2_STB=y CONFIG_AMD_HSMP=m CONFIG_AMD_WBRF=y CONFIG_ADV_SWBUTTON=m @@ -9219,6 +9251,7 @@ CONFIG_DELL_SMBIOS=m CONFIG_DELL_SMBIOS_WMI=y CONFIG_DELL_SMBIOS_SMM=y CONFIG_DELL_SMO8800=m +CONFIG_DELL_UART_BACKLIGHT=m CONFIG_DELL_WMI=m CONFIG_DELL_WMI_PRIVACY=y CONFIG_DELL_WMI_AIO=m @@ -9294,9 +9327,12 @@ CONFIG_INTEL_SMARTCONNECT=m CONFIG_INTEL_TPMI=m CONFIG_INTEL_TURBO_MAX_3=y CONFIG_INTEL_VSEC=m +CONFIG_ACPI_QUICKSTART=m +CONFIG_MEEGOPAD_ANX7428=m CONFIG_MSI_EC=m CONFIG_MSI_LAPTOP=m CONFIG_MSI_WMI=m +CONFIG_MSI_WMI_PLATFORM=m CONFIG_PCENGINES_APU2=m CONFIG_BARCO_P50_GPIO=m CONFIG_SAMSUNG_LAPTOP=m @@ -9317,6 +9353,7 @@ CONFIG_SERIAL_MULTI_INSTANTIATE=m CONFIG_MLX_PLATFORM=m CONFIG_TOUCHSCREEN_DMI=y CONFIG_INSPUR_PLATFORM_PROFILE=m +CONFIG_LENOVO_WMI_CAMERA=m CONFIG_X86_ANDROID_TABLETS=m CONFIG_FW_ATTR_CLASS=m CONFIG_INTEL_IPS=m @@ -9633,6 +9670,7 @@ CONFIG_AD7091R=m CONFIG_AD7091R5=m CONFIG_AD7091R8=m CONFIG_AD7124=m +CONFIG_AD7173=m CONFIG_AD7192=m CONFIG_AD7266=m CONFIG_AD7280=m @@ -9650,6 +9688,7 @@ CONFIG_AD7791=m CONFIG_AD7793=m CONFIG_AD7887=m CONFIG_AD7923=m +CONFIG_AD7944=m CONFIG_AD7949=m CONFIG_AD799X=m CONFIG_AD9467=m @@ -9817,6 +9856,8 @@ CONFIG_AD5592R=m CONFIG_AD5593R=m CONFIG_AD5504=m CONFIG_AD5624R_SPI=m +CONFIG_AD9739A=m +CONFIG_ADI_AXI_DAC=m CONFIG_LTC2688=m CONFIG_AD5686=m CONFIG_AD5686_SPI=m @@ -9987,6 +10028,7 @@ CONFIG_ADUX1020=m CONFIG_AL3010=m CONFIG_AL3320A=m CONFIG_APDS9300=m +CONFIG_APDS9306=m CONFIG_APDS9960=m CONFIG_AS73211=m CONFIG_BH1750=m @@ -10228,7 +10270,6 @@ CONFIG_NTB_SWITCHTEC=m # CONFIG_NTB_MSI_TEST is not set CONFIG_NTB_TRANSPORT=m CONFIG_PWM=y -CONFIG_PWM_SYSFS=y # CONFIG_PWM_DEBUG is not set CONFIG_PWM_CLK=m CONFIG_PWM_CRC=m @@ -10360,6 +10401,8 @@ CONFIG_FPGA=m CONFIG_ALTERA_PR_IP_CORE=m CONFIG_FPGA_MGR_ALTERA_PS_SPI=m CONFIG_FPGA_MGR_ALTERA_CVP=m +CONFIG_FPGA_MGR_XILINX_CORE=m +CONFIG_FPGA_MGR_XILINX_SELECTMAP=m CONFIG_FPGA_MGR_XILINX_SPI=m CONFIG_FPGA_MGR_MACHXO2_SPI=m CONFIG_FPGA_BRIDGE=m @@ -10686,6 +10729,7 @@ CONFIG_EROFS_FS_SECURITY=y CONFIG_EROFS_FS_ZIP=y CONFIG_EROFS_FS_ZIP_LZMA=y CONFIG_EROFS_FS_ZIP_DEFLATE=y +CONFIG_EROFS_FS_ZIP_ZSTD=y CONFIG_EROFS_FS_ONDEMAND=y CONFIG_EROFS_FS_PCPU_KTHREAD=y CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI=y @@ -10835,6 +10879,7 @@ CONFIG_KEYS=y CONFIG_KEYS_REQUEST_CACHE=y CONFIG_PERSISTENT_KEYRINGS=y CONFIG_TRUSTED_KEYS=m +CONFIG_HAVE_TRUSTED_KEYS=y CONFIG_TRUSTED_KEYS_TPM=y CONFIG_TRUSTED_KEYS_TEE=y CONFIG_ENCRYPTED_KEYS=m @@ -10990,7 +11035,7 @@ CONFIG_CRYPTO_RSA=y CONFIG_CRYPTO_DH=y CONFIG_CRYPTO_DH_RFC7919_GROUPS=y CONFIG_CRYPTO_ECC=y -CONFIG_CRYPTO_ECDH=m +CONFIG_CRYPTO_ECDH=y CONFIG_CRYPTO_ECDSA=y CONFIG_CRYPTO_ECRDSA=m CONFIG_CRYPTO_SM2=m @@ -11121,7 +11166,6 @@ CONFIG_CRYPTO_USER_API_RNG=m # CONFIG_CRYPTO_USER_API_RNG_CAVP is not set CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set -CONFIG_CRYPTO_STATS=y # end of Userspace interface CONFIG_CRYPTO_HASH_INFO=y @@ -11251,6 +11295,7 @@ CONFIG_ARCH_USE_SYM_ANNOTATIONS=y # CONFIG_CRYPTO_LIB_UTILS=y CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_AESCFB=y CONFIG_CRYPTO_LIB_ARC4=m CONFIG_CRYPTO_LIB_GF128MUL=m CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y @@ -11344,6 +11389,7 @@ CONFIG_ARCH_DMA_ADDR_T_64BIT=y CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED=y CONFIG_SWIOTLB=y # CONFIG_SWIOTLB_DYNAMIC is not set +CONFIG_DMA_NEED_SYNC=y CONFIG_DMA_COHERENT_POOL=y CONFIG_DMA_CMA=y # CONFIG_DMA_NUMA_CMA is not set @@ -11371,15 +11417,16 @@ CONFIG_CLZ_TAB=y CONFIG_IRQ_POLL=y CONFIG_MPILIB=y CONFIG_SIGNATURE=y -CONFIG_DIMLIB=y +CONFIG_DIMLIB=m CONFIG_OID_REGISTRY=y CONFIG_UCS2_STRING=y CONFIG_HAVE_GENERIC_VDSO=y CONFIG_GENERIC_GETTIMEOFDAY=y CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT=y CONFIG_FONT_SUPPORT=y CONFIG_FONTS=y -# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y # CONFIG_FONT_6x11 is not set # CONFIG_FONT_7x14 is not set @@ -11526,6 +11573,7 @@ CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_DEBUG_PER_CPU_MAPS is not set CONFIG_ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP=y # CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP is not set +# CONFIG_MEM_ALLOC_PROFILING is not set CONFIG_HAVE_ARCH_KASAN=y CONFIG_HAVE_ARCH_KASAN_VMALLOC=y CONFIG_CC_HAS_KASAN_GENERIC=y @@ -11551,6 +11599,7 @@ CONFIG_PANIC_ON_OOPS_VALUE=0 CONFIG_PANIC_TIMEOUT=0 CONFIG_LOCKUP_DETECTOR=y CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR_INTR_STORM=y # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set CONFIG_HAVE_HARDLOCKUP_DETECTOR_BUDDY=y CONFIG_HARDLOCKUP_DETECTOR=y @@ -11708,6 +11757,7 @@ CONFIG_HIST_TRIGGERS=y # CONFIG_RING_BUFFER_BENCHMARK is not set # CONFIG_TRACE_EVAL_MAP_FILE is not set # CONFIG_FTRACE_RECORD_RECURSION is not set +# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set # CONFIG_FTRACE_STARTUP_TEST is not set # CONFIG_FTRACE_SORT_STARTUP_TEST is not set # CONFIG_RING_BUFFER_STARTUP_TEST is not set From 9103a6bf08d622fd583fd9839d2dc4ef9b2a46e2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 17 Aug 2024 04:29:04 +0200 Subject: [PATCH 052/236] pkg/fedora: Rebase patches --- .../kernel-surface/patches/0001-iptsd.patch | 8 +++--- .../patches/0002-provides.patch | 14 +++++----- .../patches/0003-obsoletes.patch | 22 +++++++-------- .../patches/0004-default-kernel.patch | 27 +++++++++---------- .../kernel-surface/patches/0005-ipu3-fw.patch | 8 +++--- .../secureboot/0001-secureboot.patch | 12 ++++----- 6 files changed, 45 insertions(+), 46 deletions(-) diff --git a/pkg/fedora/kernel-surface/patches/0001-iptsd.patch b/pkg/fedora/kernel-surface/patches/0001-iptsd.patch index 3a9fc4c64e..6f98383ead 100644 --- a/pkg/fedora/kernel-surface/patches/0001-iptsd.patch +++ b/pkg/fedora/kernel-surface/patches/0001-iptsd.patch @@ -1,4 +1,4 @@ -From bd92f2ec163acc3a109e2fd34793553e4038b4d6 Mon Sep 17 00:00:00 2001 +From 4e9c0d02238463cd3b7dbcb6b255b553191a9761 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:33:03 +0200 Subject: [PATCH 1/5] Pull in iptsd as a weak dependency @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index c987db5886f2..1dbc56b1be3b 100644 +index 21f48fb7da63..f32befeebec3 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1001,6 +1001,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1019,6 +1019,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index c987db5886f2..1dbc56b1be3b 100644 Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -- -2.45.1 +2.46.0 diff --git a/pkg/fedora/kernel-surface/patches/0002-provides.patch b/pkg/fedora/kernel-surface/patches/0002-provides.patch index 58181abc20..83095ba134 100644 --- a/pkg/fedora/kernel-surface/patches/0002-provides.patch +++ b/pkg/fedora/kernel-surface/patches/0002-provides.patch @@ -1,4 +1,4 @@ -From 6e967041622e39df2ce421e8dcdc4aed67e8348d Mon Sep 17 00:00:00 2001 +From 519d55a4d8be9d6278ae6d842bf0d68238e670b6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:34:38 +0200 Subject: [PATCH 2/5] Let kernel-surface provide the standard package names @@ -9,7 +9,7 @@ Signed-off-by: Dorian Stoll 1 file changed, 5 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 1dbc56b1be3b..98995c878ea8 100644 +index f32befeebec3..785bc32d0544 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template @@ -653,6 +653,7 @@ Requires: kernel-core-uname-r = %{KVERREL} @@ -20,7 +20,7 @@ index 1dbc56b1be3b..98995c878ea8 100644 %endif -@@ -1333,6 +1334,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} +@@ -1351,6 +1352,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} Provides: kernel%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release}\ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1:+%{1}}}\ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -28,7 +28,7 @@ index 1dbc56b1be3b..98995c878ea8 100644 Provides: installonlypkg(kernel)\ AutoReqProv: no\ Requires(pre): findutils\ -@@ -1362,6 +1364,7 @@ against the %{?2:%{2} }kernel package.\ +@@ -1380,6 +1382,7 @@ against the %{?2:%{2} }kernel package.\ Summary: Meta package to install matching core and devel packages for a given %{?2:%{2} }kernel\ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ @@ -36,7 +36,7 @@ index 1dbc56b1be3b..98995c878ea8 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1483,6 +1486,7 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ +@@ -1501,6 +1504,7 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ Requires: realtime-setup\ %endif\ Provides: installonlypkg(kernel)\ @@ -44,7 +44,7 @@ index 1dbc56b1be3b..98995c878ea8 100644 %description %{1}\ The meta-package for the %{1} kernel\ %{nil} -@@ -1516,6 +1520,7 @@ This package provides KVM modules for package kernel%{?1:-%{1}}.\ +@@ -1534,6 +1538,7 @@ This package provides KVM modules for package kernel%{?1:-%{1}}.\ Summary: %{variant_summary}\ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: installonlypkg(kernel)\ @@ -53,5 +53,5 @@ index 1dbc56b1be3b..98995c878ea8 100644 Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ -- -2.45.1 +2.46.0 diff --git a/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch b/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch index 66048ce330..6358f53102 100644 --- a/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch +++ b/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch @@ -1,4 +1,4 @@ -From 1ff16b22002a0c7f76f74042e07d8c44d2fe3db7 Mon Sep 17 00:00:00 2001 +From 33807d72f32905d0e5627904be5263d7a126bf36 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:40:32 +0200 Subject: [PATCH 3/5] Let kernel-surface conflict with older versions of the @@ -10,7 +10,7 @@ Signed-off-by: Dorian Stoll 1 file changed, 20 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 98995c878ea8..4f3253f17121 100644 +index 785bc32d0544..890d9225edd8 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template @@ -654,6 +654,10 @@ Requires: kernel-modules-uname-r = %{KVERREL} @@ -24,7 +24,7 @@ index 98995c878ea8..4f3253f17121 100644 %endif -@@ -1336,6 +1340,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff +@@ -1354,6 +1358,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: kernel-devel = %{KVERREL}%{?1:+%{1}}\ Provides: installonlypkg(kernel)\ @@ -33,7 +33,7 @@ index 98995c878ea8..4f3253f17121 100644 AutoReqProv: no\ Requires(pre): findutils\ Requires: findutils\ -@@ -1365,6 +1371,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ +@@ -1383,6 +1389,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ Provides: kernel-devel-matched = %{specrpmversion}-%{release}\ @@ -42,7 +42,7 @@ index 98995c878ea8..4f3253f17121 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1397,6 +1405,8 @@ Provides: kernel%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix +@@ -1415,6 +1423,8 @@ Provides: kernel%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -51,7 +51,7 @@ index 98995c878ea8..4f3253f17121 100644 AutoReq: no\ AutoProv: yes\ %description %{?1:%{1}-}modules-internal\ -@@ -1418,6 +1428,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? +@@ -1436,6 +1446,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -60,7 +60,7 @@ index 98995c878ea8..4f3253f17121 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-extra-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1441,6 +1453,8 @@ Provides: installonlypkg(kernel-module)\ +@@ -1459,6 +1471,8 @@ Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -69,7 +69,7 @@ index 98995c878ea8..4f3253f17121 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1463,6 +1477,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: +@@ -1481,6 +1495,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -78,7 +78,7 @@ index 98995c878ea8..4f3253f17121 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1485,6 +1501,8 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ +@@ -1503,6 +1519,8 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ %if "%{1}" == "rt" || "%{1}" == "rt-debug"\ Requires: realtime-setup\ %endif\ @@ -87,7 +87,7 @@ index 98995c878ea8..4f3253f17121 100644 Provides: installonlypkg(kernel)\ Provides: kernel = %{KVERREL}+%{1}\ %description %{1}\ -@@ -1521,6 +1539,8 @@ Summary: %{variant_summary}\ +@@ -1539,6 +1557,8 @@ Summary: %{variant_summary}\ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: installonlypkg(kernel)\ Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{?1:+%{1}}\ @@ -97,5 +97,5 @@ index 98995c878ea8..4f3253f17121 100644 Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ -- -2.45.1 +2.46.0 diff --git a/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch b/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch index 52c8bc6306..4a00496528 100644 --- a/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch +++ b/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch @@ -1,4 +1,4 @@ -From 64bb7e9daea6e836c3eb8334368ea9cd651ce8db Mon Sep 17 00:00:00 2001 +From ddb9b1b93df3bf75843ab952534a39a7e8dd7711 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:41:11 +0200 Subject: [PATCH 4/5] Install scripts and service files for keeping the surface @@ -6,14 +6,14 @@ Subject: [PATCH 4/5] Install scripts and service files for keeping the surface Signed-off-by: Dorian Stoll --- - redhat/kernel.spec.template | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) + redhat/kernel.spec.template | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 4f3253f17121..3ce7fbec4beb 100644 +index 890d9225edd8..68b06ba0d4b1 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -974,6 +974,11 @@ Source4000: README.rst +@@ -992,6 +992,11 @@ Source4000: README.rst Source4001: rpminspect.yaml Source4002: gating.yaml @@ -25,7 +25,7 @@ index 4f3253f17121..3ce7fbec4beb 100644 ## Patches needed for building this package %if !%{nopatches} -@@ -1007,6 +1012,7 @@ Requires(pre): %{initrd_prereq}\ +@@ -1025,6 +1030,7 @@ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ Recommends: iptsd\ @@ -33,7 +33,7 @@ index 4f3253f17121..3ce7fbec4beb 100644 Requires(preun): systemd >= 200\ Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -@@ -1021,6 +1027,14 @@ AutoProv: yes\ +@@ -1039,6 +1045,13 @@ AutoProv: yes\ %{nil} @@ -43,12 +43,11 @@ index 4f3253f17121..3ce7fbec4beb 100644 +This package provides a systemd service that will automatically keep +the surface kernel as the default kernel in GRUB, even if a newer stock +kernel has been installed. -+ + %package doc Summary: Various documentation bits found in the kernel source Group: Documentation -@@ -3091,6 +3105,11 @@ find Documentation -type d | xargs chmod u+w +@@ -3170,6 +3183,11 @@ find Documentation -type d | xargs chmod u+w cd linux-%{KVERREL} @@ -57,10 +56,10 @@ index 4f3253f17121..3ce7fbec4beb 100644 +install -D -m755 "%{SOURCE4102}" -t "%{buildroot}%{_bindir}" +install -D -m755 "%{SOURCE4103}" -t "%{buildroot}%{_presetdir}" + - %if %{with_doc} - docdir=$RPM_BUILD_ROOT%{_datadir}/doc/kernel-doc-%{specversion}-%{pkgrelease} + # re-define RPM_VMLINUX_H, because it doesn't carry over from %build + RPM_VMLINUX_H="$(cat ../vmlinux_h_path)" -@@ -3347,6 +3366,15 @@ popd +@@ -3441,6 +3459,15 @@ popd ### scripts ### @@ -76,7 +75,7 @@ index 4f3253f17121..3ce7fbec4beb 100644 %if %{with_tools} %post -n %{package_name}-tools-libs /sbin/ldconfig -@@ -3810,6 +3838,12 @@ fi\ +@@ -3904,6 +3931,12 @@ fi\ %{_libexecdir}/kselftests %endif @@ -90,5 +89,5 @@ index 4f3253f17121..3ce7fbec4beb 100644 %if %{with_up_base} %ifnarch %nobuildarches noarch -- -2.45.1 +2.46.0 diff --git a/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch b/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch index fe7a70bec2..bd2fa4d184 100644 --- a/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch +++ b/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch @@ -1,4 +1,4 @@ -From 076cb99d65797ebc56a798976dc1b043ff58687a Mon Sep 17 00:00:00 2001 +From 47af57cd4a28cde0cecfdbb7d55197569a5af721 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Mon, 29 Jan 2024 19:26:41 +0100 Subject: [PATCH 5/5] Pull in intel-vsc-firmware @@ -9,10 +9,10 @@ This package contains the IPU3 firmware needed for camera support. 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 3ce7fbec4beb..e6bece22b1f3 100644 +index 68b06ba0d4b1..40882a465616 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1011,6 +1011,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1029,6 +1029,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index 3ce7fbec4beb..e6bece22b1f3 100644 Recommends: %{package_name}-default-watchdog\ Requires(preun): systemd >= 200\ -- -2.45.1 +2.46.0 diff --git a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch index ccf22c40f3..4fff32a0da 100644 --- a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch +++ b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 9fe406af6d54768c681817a91cf28e6159725c05 Mon Sep 17 00:00:00 2001 +From 4283ba47e3bfc34f6d4253b9ece50622d3815b97 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:45:33 +0200 Subject: [PATCH] Use a custom key and certificate for Secure Boot signing @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index e6bece22b1f3..c5995edff65b 100644 +index 21f48fb7da63..d411e2cd2eda 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -764,6 +764,7 @@ BuildRequires: system-sb-certs +@@ -759,6 +759,7 @@ BuildRequires: system-sb-certs %ifarch x86_64 aarch64 BuildRequires: nss-tools BuildRequires: pesign >= 0.10-4 @@ -20,7 +20,7 @@ index e6bece22b1f3..c5995edff65b 100644 %endif %endif %endif -@@ -827,6 +828,13 @@ Source13: redhatsecureboot501.cer +@@ -830,6 +831,13 @@ Source13: redhatsecureboot501.cer %define signing_key_filename kernel-signing-s390.cer %endif @@ -34,7 +34,7 @@ index e6bece22b1f3..c5995edff65b 100644 # Fedora/ELN pesign macro expects to see these cert file names, see: # https://github.com/rhboot/pesign/blob/main/src/pesign-rpmbuild-helper.in#L216 %if 0%{?fedora}%{?eln} -@@ -2188,7 +2196,7 @@ BuildKernel() { +@@ -2192,7 +2200,7 @@ BuildKernel() { %ifarch x86_64 aarch64 %{log_msg "Sign kernel image"} @@ -44,5 +44,5 @@ index e6bece22b1f3..c5995edff65b 100644 %ifarch s390x ppc64le if [ -x /usr/bin/rpm-sign ]; then -- -2.45.1 +2.46.0 From 43f0d7e8550b78f5541dbdda6afe4a68fb5889c7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Sep 2024 04:05:51 +0200 Subject: [PATCH 053/236] Remove support for Fedora 38 --- .github/workflows/fedora-38.yml | 125 -------------------------------- 1 file changed, 125 deletions(-) delete mode 100644 .github/workflows/fedora-38.yml diff --git a/.github/workflows/fedora-38.yml b/.github/workflows/fedora-38.yml deleted file mode 100644 index 9b151aa7a3..0000000000 --- a/.github/workflows/fedora-38.yml +++ /dev/null @@ -1,125 +0,0 @@ -name: Fedora 38 - -env: - FEDORA: 38 - GPG_KEY_ID: 56C464BAAC421453 - -on: - push: - tags: - - 'fedora-38-*' - - repository_dispatch: - workflow_dispatch: - -jobs: - build: - name: Build Kernel - runs-on: ubuntu-latest - steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 5120 - remove-dotnet: true - remove-android: true - remove-docker-images: true - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Initialize containers - run: | - bash ./.github/scripts/container/create.sh \ - registry.fedoraproject.org/fedora:${{ env.FEDORA }} - - - name: Install build dependencies - run: | - bash ./.github/scripts/container/exec.sh \ - -- \ - bash ./.github/scripts/package/fedora.sh setup-builddeps - - - name: Setup secureboot certificate - env: - SB_KEY: ${{ secrets.SURFACE_SB_KEY }} - run: | - bash ./.github/scripts/container/exec.sh \ - -e SB_KEY \ - -- \ - bash ./.github/scripts/package/fedora.sh setup-secureboot - - - name: Build packages - run: | - bash ./.github/scripts/container/exec.sh \ - -- \ - bash ./.github/scripts/package/fedora.sh build-packages - - - name: Sign packages - env: - GPG_KEY: ${{ secrets.LINUX_SURFACE_GPG_KEY }} - run: | - bash ./.github/scripts/container/exec.sh \ - -e GPG_KEY \ - -e GPG_KEY_ID \ - -- \ - bash ./.github/scripts/package/fedora.sh sign-packages - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: fedora-${{ env.FEDORA }}-latest - path: pkg/fedora/kernel-surface/out/x86_64 - - release: - name: Publish release - if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/') - needs: [build] - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v3 - with: - name: fedora-${{ env.FEDORA }}-latest - path: fedora-${{ env.FEDORA }}-latest - - - name: Upload assets - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} - file: ./*-latest/* - tag: ${{ github.ref }} - overwrite: true - file_glob: true - - repo: - name: Update package repository - needs: [release] - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Download artifacts - uses: actions/download-artifact@v3 - with: - name: fedora-${{ env.FEDORA }}-latest - path: fedora-${{ env.FEDORA }}-latest - - - name: Initialize containers - run: | - bash ./.github/scripts/container/create.sh \ - registry.fedoraproject.org/fedora:${{ env.FEDORA }} - - - name: Update repository - env: - SURFACEBOT_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} - GIT_REF: ${{ github.ref }} - BRANCH_STAGING: u/staging - run: | - bash ./.github/scripts/container/exec.sh \ - -e SURFACEBOT_TOKEN \ - -e GIT_REF \ - -e BRANCH_STAGING \ - -e GITHUB_REPOSITORY \ - -- \ - bash ./.github/scripts/repository/fedora.sh ${{ env.FEDORA }} \ No newline at end of file From 11438c3e2a3b528a9691f0b99b402ed655567a03 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Sep 2024 04:06:07 +0200 Subject: [PATCH 054/236] Add support for Fedora 41 --- .github/workflows/fedora-41.yml | 125 ++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 .github/workflows/fedora-41.yml diff --git a/.github/workflows/fedora-41.yml b/.github/workflows/fedora-41.yml new file mode 100644 index 0000000000..a3e9066f21 --- /dev/null +++ b/.github/workflows/fedora-41.yml @@ -0,0 +1,125 @@ +name: Fedora 41 + +env: + FEDORA: 41 + GPG_KEY_ID: 56C464BAAC421453 + +on: + push: + tags: + - 'fedora-41-*' + + repository_dispatch: + workflow_dispatch: + +jobs: + build: + name: Build Kernel + runs-on: ubuntu-latest + steps: + - name: Maximize disk space + uses: easimon/maximize-build-space@master + with: + root-reserve-mb: 5120 + remove-dotnet: true + remove-android: true + remove-docker-images: true + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Initialize containers + run: | + bash ./.github/scripts/container/create.sh \ + registry.fedoraproject.org/fedora:${{ env.FEDORA }} + + - name: Install build dependencies + run: | + bash ./.github/scripts/container/exec.sh \ + -- \ + bash ./.github/scripts/package/fedora.sh setup-builddeps + + - name: Setup secureboot certificate + env: + SB_KEY: ${{ secrets.SURFACE_SB_KEY }} + run: | + bash ./.github/scripts/container/exec.sh \ + -e SB_KEY \ + -- \ + bash ./.github/scripts/package/fedora.sh setup-secureboot + + - name: Build packages + run: | + bash ./.github/scripts/container/exec.sh \ + -- \ + bash ./.github/scripts/package/fedora.sh build-packages + + - name: Sign packages + env: + GPG_KEY: ${{ secrets.LINUX_SURFACE_GPG_KEY }} + run: | + bash ./.github/scripts/container/exec.sh \ + -e GPG_KEY \ + -e GPG_KEY_ID \ + -- \ + bash ./.github/scripts/package/fedora.sh sign-packages + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: fedora-${{ env.FEDORA }}-latest + path: pkg/fedora/kernel-surface/out/x86_64 + + release: + name: Publish release + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/') + needs: [build] + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: fedora-${{ env.FEDORA }}-latest + path: fedora-${{ env.FEDORA }}-latest + + - name: Upload assets + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + file: ./*-latest/* + tag: ${{ github.ref }} + overwrite: true + file_glob: true + + repo: + name: Update package repository + needs: [release] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: fedora-${{ env.FEDORA }}-latest + path: fedora-${{ env.FEDORA }}-latest + + - name: Initialize containers + run: | + bash ./.github/scripts/container/create.sh \ + registry.fedoraproject.org/fedora:${{ env.FEDORA }} + + - name: Update repository + env: + SURFACEBOT_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + GIT_REF: ${{ github.ref }} + BRANCH_STAGING: u/staging + run: | + bash ./.github/scripts/container/exec.sh \ + -e SURFACEBOT_TOKEN \ + -e GIT_REF \ + -e BRANCH_STAGING \ + -e GITHUB_REPOSITORY \ + -- \ + bash ./.github/scripts/repository/fedora.sh ${{ env.FEDORA }} From 41231b614f9a7d070a0e13b21cb236a8fae638df Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Sep 2024 04:06:56 +0200 Subject: [PATCH 055/236] Update v6.10 patches Changes: - Add lockdown_hibernate kernel parameter to allow hibernation when lockdown is enabled. See [1] and [2] for details. [1]: https://github.com/linux-surface/kernel/pull/158 [2]: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee - Address some review comments by @ashevche - Rebase onto v6.10.10 Links: - kernel: https://github.com/linux-surface/kernel/commit/4b6f46e5842a622a7e63d1d0822f0ac22019b040 --- patches/6.10/0001-secureboot.patch | 77 ++++++++++++- patches/6.10/0002-surface3-oemb.patch | 2 +- patches/6.10/0003-mwifiex.patch | 8 +- patches/6.10/0004-ath10k.patch | 2 +- patches/6.10/0005-ipts.patch | 8 +- patches/6.10/0006-ithc.patch | 4 +- patches/6.10/0007-surface-sam.patch | 81 +++----------- patches/6.10/0008-surface-sam-over-hid.patch | 107 +++++++------------ patches/6.10/0009-surface-button.patch | 4 +- patches/6.10/0010-surface-typecover.patch | 6 +- patches/6.10/0011-surface-shutdown.patch | 2 +- patches/6.10/0012-surface-gpe.patch | 2 +- patches/6.10/0013-cameras.patch | 37 +++---- patches/6.10/0014-amd-gpio.patch | 4 +- patches/6.10/0015-rtc.patch | 2 +- 15 files changed, 170 insertions(+), 176 deletions(-) diff --git a/patches/6.10/0001-secureboot.patch b/patches/6.10/0001-secureboot.patch index f1dc041286..5f70268f23 100644 --- a/patches/6.10/0001-secureboot.patch +++ b/patches/6.10/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 252c5b2e65865a2a3aa6a5400f204c47d22490ee Mon Sep 17 00:00:00 2001 +From f042429d0ea3d440fa70f9c51c8197bb208f0a88 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,3 +35,78 @@ index b5c79f43359b..a1bbedd989e4 100644 -- 2.46.0 +From db11088db25ece8759f2db44ae62b144575a3649 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index c82446cef8e2..2ae1a6fda7f9 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3000,6 +3000,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 0a213f69a9e4..8e4f9dcc9f4c 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1422,6 +1423,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1480,3 +1487,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.46.0 + diff --git a/patches/6.10/0002-surface3-oemb.patch b/patches/6.10/0002-surface3-oemb.patch index 82db24aca0..75bf3ef7a6 100644 --- a/patches/6.10/0002-surface3-oemb.patch +++ b/patches/6.10/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 1146270e92aee0b612dfe695bcf8f7131a19bcf3 Mon Sep 17 00:00:00 2001 +From 3b00df63072f59df6b111ad853b87094b3536442 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.10/0003-mwifiex.patch b/patches/6.10/0003-mwifiex.patch index 8e214c3fd8..7f417177e2 100644 --- a/patches/6.10/0003-mwifiex.patch +++ b/patches/6.10/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 800e9cfe84a3eadd4dc9ae700940068e77fa8a12 Mon Sep 17 00:00:00 2001 +From 4ed887721124fdef2427143d1df5c56f42527b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.46.0 -From d51c5a356fee57c99a8d181825f8f941f34749d7 Mon Sep 17 00:00:00 2001 +From 894aa28465f66434a8c253eee50347f682c40117 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.46.0 -From 317cde3654592dcb3e072d0d2fe7b4e5598cc078 Mon Sep 17 00:00:00 2001 +From bca01a7cadbd3152491c45ae9d427478447cc483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 789c492df6fa..1e766b6c1f9a 100644 +index 0927f51867c2..3d3573829631 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; diff --git a/patches/6.10/0004-ath10k.patch b/patches/6.10/0004-ath10k.patch index 886f510947..c420e572bd 100644 --- a/patches/6.10/0004-ath10k.patch +++ b/patches/6.10/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 268a79fb66862ef22294397a425fd074fc336c34 Mon Sep 17 00:00:00 2001 +From 285063f8ccb7722b6eb27a6401fed87c86fd2e7f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.10/0005-ipts.patch b/patches/6.10/0005-ipts.patch index 31144224c2..67e11af280 100644 --- a/patches/6.10/0005-ipts.patch +++ b/patches/6.10/0005-ipts.patch @@ -1,4 +1,4 @@ -From 9904c59dbdd422b811974893bab69fc5b4bc9a03 Mon Sep 17 00:00:00 2001 +From 60cbae0f851d06cd4c356b29377ecbadfb08f874 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 6589635f8ba3..a1df48a434e2 100644 -- 2.46.0 -From b0d9ceae2f95a4e4093b07580bedc10821374555 Mon Sep 17 00:00:00 2001 +From 681a57dea0faeceb03b50752abbafb85341b981c Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index f55ec1fd7942..8d95579436a9 100644 +index e9bea0305c26..6ee97bf7b6a9 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -40,6 +40,11 @@ @@ -144,7 +144,7 @@ index f55ec1fd7942..8d95579436a9 100644 -- 2.46.0 -From ee1ebc3f9ec7a8418f418902817b5c5f4b51c21d Mon Sep 17 00:00:00 2001 +From 56f5368c0bfde7b931fcb183cc779db625978f51 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.10/0006-ithc.patch b/patches/6.10/0006-ithc.patch index 3a28a55bfd..d8afcc34a6 100644 --- a/patches/6.10/0006-ithc.patch +++ b/patches/6.10/0006-ithc.patch @@ -1,4 +1,4 @@ -From 0d0e07366b425e953d6dab698d62dbe9a7546994 Mon Sep 17 00:00:00 2001 +From 19b03c0a9c68f00487ed8c07163e819da9c63fdd Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index e4a70886678c..961a33b87c24 100644 -- 2.46.0 -From 19a947aa5cc417bd43656cf9d8bf010abdc6bc3f Mon Sep 17 00:00:00 2001 +From 9f355143af2087aff4c4c1a6db46e6595e8ec5d4 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.10/0007-surface-sam.patch b/patches/6.10/0007-surface-sam.patch index 7eae09105a..13ebbe5b50 100644 --- a/patches/6.10/0007-surface-sam.patch +++ b/patches/6.10/0007-surface-sam.patch @@ -1,59 +1,4 @@ -From 17af44bcfe971e7b9dddad3735fad70bbda3fbf9 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Fri, 19 Apr 2024 20:41:47 +0200 -Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is - destroyed in probe - -There is a small window in ssam_serial_hub_probe() where the controller -is initialized but has not been started yet. Specifically, between -ssam_controller_init() and ssam_controller_start(). Any failure in this -window, for example caused by a failure of serdev_device_open(), -currently results in an incorrect warning being emitted. - -In particular, any failure in this window results in the controller -being destroyed via ssam_controller_destroy(). This function checks the -state of the controller and, in an attempt to validate that the -controller has been cleanly shut down before we try and deallocate any -resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. - -However, since we have only just initialized the controller and have not -yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this -is the only point at which the controller has this state, as it will -change after we start the controller with ssam_controller_start() and -never revert back. Further, at this point no communication has taken -place and the sender and receiver threads have not been started yet (and -we may not even have an open serdev device either). - -Therefore, it is perfectly safe to call ssam_controller_destroy() with a -state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the -warning currently being emitted is incorrect. Fix it by extending the -check. - -Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/platform/surface/aggregator/controller.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c -index 7fc602e01487..7e89f547999b 100644 ---- a/drivers/platform/surface/aggregator/controller.c -+++ b/drivers/platform/surface/aggregator/controller.c -@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) - if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) - return; - -- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); -+ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && -+ ctrl->state != SSAM_CONTROLLER_INITIALIZED); - - /* - * Note: New events could still have been received after the previous --- -2.46.0 - -From 00b833401e8060eb50db269e0681383454a74848 Mon Sep 17 00:00:00 2001 +From 1c0c81136657ad8656e5d713d0d8282d70413e53 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Oct 2023 14:57:11 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -86,7 +31,7 @@ index 1c4d74db08c9..f826489dc69d 100644 -- 2.46.0 -From 9e13165394bf1898d05c7d5a4a5adb1767d2307e Mon Sep 17 00:00:00 2001 +From 74e058609a1229cfd478690ae2ad0fbb209ee6ed Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 19:47:00 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -156,7 +101,7 @@ index f826489dc69d..ef59a7b66667 100644 -- 2.46.0 -From 83719d2cd70ad6ac1df993782e757ded15e881cc Mon Sep 17 00:00:00 2001 +From 61ed1a703286c45a6f9de31053a8041e7e54cd4d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 20:05:57 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -174,7 +119,7 @@ Patchset: surface-sam 1 file changed, 19 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index ef59a7b66667..70a2ea5a1957 100644 +index ef59a7b66667..a20ccf49731c 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -273,6 +273,22 @@ static const struct software_node *ssam_node_group_sl5[] = { @@ -205,7 +150,7 @@ index ef59a7b66667..70a2ea5a1957 100644 { "MSHW0350", (unsigned long)ssam_node_group_sl5 }, + /* Surface Laptop 6 */ -+ { "MSHW0530", (unsigned long)ssam_node_group_sl5 }, ++ { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + /* Surface Laptop Go 1 */ { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, @@ -213,7 +158,7 @@ index ef59a7b66667..70a2ea5a1957 100644 -- 2.46.0 -From c188646846cc6e9db1134eb62208d088ce615312 Mon Sep 17 00:00:00 2001 +From be2709e2a0ddebba3887d730a2e61b7bec2a06f2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -441,7 +386,7 @@ index 000000000000..48c3e826713f -- 2.46.0 -From 31d334453ebc65b7868bf33b1963553586e64fa3 Mon Sep 17 00:00:00 2001 +From 15ba0027e4d72f580255f8776ee251c94f81cab1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -636,7 +581,7 @@ index 48c3e826713f..4c08926139db 100644 -- 2.46.0 -From 36174000616d130e9b4655d69eb3bd5b07adbecb Mon Sep 17 00:00:00 2001 +From b80e50b1a90e22d3a200b085cac567905e56543c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:47:47 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -648,7 +593,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 70a2ea5a1957..6b568804f70b 100644 +index a20ccf49731c..2b20c74bbe6d 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -265,7 +265,9 @@ static const struct software_node *ssam_node_group_sl5[] = { @@ -665,7 +610,7 @@ index 70a2ea5a1957..6b568804f70b 100644 -- 2.46.0 -From e32f317be4ad620fb6683b62ad9e883f37e17f57 Mon Sep 17 00:00:00 2001 +From 06973bc3db29f5d009d4de6298e0496490c811ee Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:48:02 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -677,7 +622,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 6b568804f70b..9046df95c043 100644 +index 2b20c74bbe6d..1e7e7ebeb074 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -312,7 +312,9 @@ static const struct software_node *ssam_node_group_sls2[] = { @@ -694,7 +639,7 @@ index 6b568804f70b..9046df95c043 100644 -- 2.46.0 -From ebf64f6dcf1bdf0dbe80b5ec5e3d4b8a6cfab41e Mon Sep 17 00:00:00 2001 +From 01cab9f250e8dc4b6a2e784467487f7eb03e7afe Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 28 Jun 2024 22:31:37 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Support for @@ -706,7 +651,7 @@ Patchset: surface-sam 1 file changed, 22 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 9046df95c043..058f4edd8b66 100644 +index 1e7e7ebeb074..ec9eb4d375b9 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -377,6 +377,25 @@ static const struct software_node *ssam_node_group_sp9[] = { diff --git a/patches/6.10/0008-surface-sam-over-hid.patch b/patches/6.10/0008-surface-sam-over-hid.patch index d07a2851fe..43c028ab40 100644 --- a/patches/6.10/0008-surface-sam-over-hid.patch +++ b/patches/6.10/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 8dac7a369f2f1c461750a3c3f6d93caae9566ace Mon Sep 17 00:00:00 2001 +From 6e7285d272dd52c42f6e2f17264a88abe8460a99 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -51,14 +51,14 @@ quirk-like interface into the I2C core. Signed-off-by: Maximilian Luz Patchset: surface-sam-over-hid --- - drivers/i2c/i2c-core-acpi.c | 35 +++++++++++++++++++++++++++++++++++ - 1 file changed, 35 insertions(+) + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index 14ae0cfc325e..a3a9f81fb47f 100644 +index 14ae0cfc325e..6197c5252d2a 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c -@@ -639,6 +639,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, +@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, return (ret == 1) ? 0 : -EIO; } @@ -66,7 +66,7 @@ index 14ae0cfc325e..a3a9f81fb47f 100644 + u8 *data, u8 data_len) +{ + struct i2c_msg msgs[1]; -+ int ret = AE_OK; ++ int ret; + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags; @@ -74,7 +74,6 @@ index 14ae0cfc325e..a3a9f81fb47f 100644 + msgs[0].buf = data; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ + if (ret < 0) { + dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); + return ret; @@ -87,7 +86,7 @@ index 14ae0cfc325e..a3a9f81fb47f 100644 static acpi_status i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, -@@ -740,6 +762,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, +@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, } break; @@ -110,7 +109,7 @@ index 14ae0cfc325e..a3a9f81fb47f 100644 -- 2.46.0 -From fe964119c511036a560d1dfcbec1196ae4ed1621 Mon Sep 17 00:00:00 2001 +From 0ce0983a58d19778a010c55e6ca16e344a28b4a1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -128,8 +127,8 @@ Patchset: surface-sam-over-hid --- drivers/platform/surface/Kconfig | 7 + drivers/platform/surface/Makefile | 1 + - .../surface/surfacebook1_dgpu_switch.c | 162 ++++++++++++++++++ - 3 files changed, 170 insertions(+) + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig @@ -164,35 +163,28 @@ index 53344330939b..7efcd0cdb532 100644 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 000000000000..8b816ed8f35c +index 000000000000..68db237734a1 --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c -@@ -0,0 +1,162 @@ +@@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + -+#include +#include +#include +#include + -+ -+#ifdef pr_fmt -+#undef pr_fmt -+#endif -+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ -+ -+ -+static const guid_t dgpu_sw_guid = GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, -+ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); + +#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" +#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" +#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" + -+ +static int sb1_dgpu_sw_dsmcall(void) +{ -+ union acpi_object *ret; ++ union acpi_object *obj; + acpi_handle handle; + acpi_status status; + @@ -200,67 +192,66 @@ index 000000000000..8b816ed8f35c + if (status) + return -EINVAL; + -+ ret = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); -+ if (!ret) ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) + return -EINVAL; + -+ ACPI_FREE(ret); ++ ACPI_FREE(obj); + return 0; +} + -+static int sb1_dgpu_sw_hgon(void) ++static int sb1_dgpu_sw_hgon(struct device *dev) +{ + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + + status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); + if (status) { -+ pr_err("failed to run HGON: %d\n", status); ++ dev_err(dev, "failed to run HGON: %d\n", status); + return -EINVAL; + } + -+ if (buf.pointer) -+ ACPI_FREE(buf.pointer); ++ ACPI_FREE(buf.pointer); + -+ pr_info("turned-on dGPU via HGON\n"); ++ dev_info(dev, "turned-on dGPU via HGON\n"); + return 0; +} + -+static int sb1_dgpu_sw_hgof(void) ++static int sb1_dgpu_sw_hgof(struct device *dev) +{ + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + + status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); + if (status) { -+ pr_err("failed to run HGOF: %d\n", status); ++ dev_err(dev, "failed to run HGOF: %d\n", status); + return -EINVAL; + } + -+ if (buf.pointer) -+ ACPI_FREE(buf.pointer); ++ ACPI_FREE(buf.pointer); + -+ pr_info("turned-off dGPU via HGOF\n"); ++ dev_info(dev, "turned-off dGPU via HGOF\n"); + return 0; +} + -+ +static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ -+ int status, value; ++ bool value; ++ int status; + -+ status = kstrtoint(buf, 0, &value); ++ status = kstrtobool(buf, &value); + if (status < 0) + return status; + -+ if (value != 1) -+ return -EINVAL; ++ if (!value) ++ return 0; + + status = sb1_dgpu_sw_dsmcall(); + + return status < 0 ? status : len; +} ++static DEVICE_ATTR_WO(dgpu_dsmcall); + +static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) @@ -273,37 +264,20 @@ index 000000000000..8b816ed8f35c + return status; + + if (power) -+ status = sb1_dgpu_sw_hgon(); ++ status = sb1_dgpu_sw_hgon(dev); + else -+ status = sb1_dgpu_sw_hgof(); ++ status = sb1_dgpu_sw_hgof(dev); + + return status < 0 ? status : len; +} -+ -+static DEVICE_ATTR_WO(dgpu_dsmcall); +static DEVICE_ATTR_WO(dgpu_power); + +static struct attribute *sb1_dgpu_sw_attrs[] = { + &dev_attr_dgpu_dsmcall.attr, + &dev_attr_dgpu_power.attr, -+ NULL, ++ NULL +}; -+ -+static const struct attribute_group sb1_dgpu_sw_attr_group = { -+ .attrs = sb1_dgpu_sw_attrs, -+}; -+ -+ -+static int sb1_dgpu_sw_probe(struct platform_device *pdev) -+{ -+ return sysfs_create_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); -+} -+ -+static int sb1_dgpu_sw_remove(struct platform_device *pdev) -+{ -+ sysfs_remove_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); -+ return 0; -+} ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); + +/* + * The dGPU power seems to be actually handled by MSHW0040. However, that is @@ -312,17 +286,16 @@ index 000000000000..8b816ed8f35c + */ +static const struct acpi_device_id sb1_dgpu_sw_match[] = { + { "MSHW0041", }, -+ { }, ++ { } +}; +MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); + +static struct platform_driver sb1_dgpu_sw = { -+ .probe = sb1_dgpu_sw_probe, -+ .remove = sb1_dgpu_sw_remove, + .driver = { + .name = "surfacebook1_dgpu_switch", + .acpi_match_table = sb1_dgpu_sw_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, + }, +}; +module_platform_driver(sb1_dgpu_sw); diff --git a/patches/6.10/0009-surface-button.patch b/patches/6.10/0009-surface-button.patch index 34a615d252..7a8f8aceb3 100644 --- a/patches/6.10/0009-surface-button.patch +++ b/patches/6.10/0009-surface-button.patch @@ -1,4 +1,4 @@ -From d811fb8e32e1327baf131c85522aee281f4281af Mon Sep 17 00:00:00 2001 +From 81f45954e36d6ce9e5f217bde8149cb3f5d1ff6c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index f6d060377d18..b8603f74eb28 100644 -- 2.46.0 -From e21138766921f4a22e710b4858f75f98e308c61d Mon Sep 17 00:00:00 2001 +From 94aa734ec2fd6eef10ae5155c1ba2e6d063f73f8 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.10/0010-surface-typecover.patch b/patches/6.10/0010-surface-typecover.patch index cad46568fa..7cd7e1ebe7 100644 --- a/patches/6.10/0010-surface-typecover.patch +++ b/patches/6.10/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From a19b7328ccb6c090354593fa039e5283140a5e69 Mon Sep 17 00:00:00 2001 +From 1525b314caae3999007352990890172d87358d8c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 13171454f959..a83beefd25f3 100644 -- 2.46.0 -From 99fb371b3a11e3c3d67d29673508911b81a1408c Mon Sep 17 00:00:00 2001 +From 0e0e42f91887b34bb83cc84d29228b7464001558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -272,7 +272,7 @@ index 56fc78841f24..a266449065a0 100644 -- 2.46.0 -From 7b797164a3f2ecf402b8f24d5123e74914b09064 Mon Sep 17 00:00:00 2001 +From 393718e523dac04097a037778d4896e88b4a0d96 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.10/0011-surface-shutdown.patch b/patches/6.10/0011-surface-shutdown.patch index 87316e45a8..f8cebf0583 100644 --- a/patches/6.10/0011-surface-shutdown.patch +++ b/patches/6.10/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From e26e0570db9e2dbb37e075ef7a88270fe793fb94 Mon Sep 17 00:00:00 2001 +From 85df3c0422688b4010a1cd9079511b1a0e2b38a8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.10/0012-surface-gpe.patch b/patches/6.10/0012-surface-gpe.patch index 0dd835c3cc..a6da37aa09 100644 --- a/patches/6.10/0012-surface-gpe.patch +++ b/patches/6.10/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From bed56a2a67db8c5934008ed83fa0bbd71360ab02 Mon Sep 17 00:00:00 2001 +From e17a29ddcf58b4e9b43234c8ad4b6a73fddbe0d4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.10/0013-cameras.patch b/patches/6.10/0013-cameras.patch index 9f36fc5c40..9a6b91e2de 100644 --- a/patches/6.10/0013-cameras.patch +++ b/patches/6.10/0013-cameras.patch @@ -1,4 +1,4 @@ -From 0a70aafbfa7ad39054c0974e428935c9d9e48cf1 Mon Sep 17 00:00:00 2001 +From 6a5e5f7496e5e5a86dd43da8bdf955fb2cb330e5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,7 +58,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 503773707e01..a292a20c4315 100644 +index cdc5a74092c7..e3a16c14a29e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2176,6 +2176,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, @@ -74,7 +74,7 @@ index 503773707e01..a292a20c4315 100644 -- 2.46.0 -From bdae5b6a0e462398fa6035a2f0de8efae144abe4 Mon Sep 17 00:00:00 2001 +From 839e164bf1650a36b9c5c955035e900cdea017da Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 8d95579436a9..cbfb59ed5985 100644 +index 6ee97bf7b6a9..a1f86bde277a 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -45,6 +45,13 @@ @@ -184,7 +184,7 @@ index 8d95579436a9..cbfb59ed5985 100644 -- 2.46.0 -From aa044fab288ddf51ad963effe090d0b548d83243 Mon Sep 17 00:00:00 2001 +From b9a1edc6bbf4fa65e14a530bf353fea2838cafc6 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 1e107fd49f82..e3e1696e7f0e 100644 -- 2.46.0 -From 12da0a015e6d71071561668950a4fb5e33220af8 Mon Sep 17 00:00:00 2001 +From 139109dc8f358284091d856e8c8a96117a359d8e Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -239,19 +239,20 @@ polarity of the pin to match the driver's expectation. Signed-off-by: Daniel Scally Patchset: cameras --- - drivers/platform/x86/intel/int3472/discrete.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 07b302e09340..1d3097bc7e48 100644 +index 07b302e09340..baad1e50ca81 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 +@@ -83,12 +83,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 const char *func, u32 polarity) { int ret; + const struct acpi_device_id ov7251_ids[] = { + { "INT347E" }, ++ { } + }; if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { @@ -267,7 +268,7 @@ index 07b302e09340..1d3097bc7e48 100644 + */ + if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { + func = "enable"; -+ polarity = GPIO_ACTIVE_HIGH; ++ polarity ^= GPIO_ACTIVE_LOW; + } + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], @@ -276,7 +277,7 @@ index 07b302e09340..1d3097bc7e48 100644 -- 2.46.0 -From ddc65d1014592b1fe4d6e16c9badcc928e577b3b Mon Sep 17 00:00:00 2001 +From 8d89dfb5a37b9bf23909612e70cded7e0e6713fe Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -315,7 +316,7 @@ index 30f61e04ecaf..9c1292ca8552 100644 -- 2.46.0 -From ea560c5a7e55695438ac99fbd363352991fe62af Mon Sep 17 00:00:00 2001 +From b528a28460ee1cd74d6a5c9fd156cd3275124610 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -366,7 +367,7 @@ index 89c7192148df..44eca113e772 100644 -- 2.46.0 -From 0c59f9eee1c8dc8ea4d99f8b1a07b342ef5e425d Mon Sep 17 00:00:00 2001 +From a906d692dab6a3d74a30e3d92b8419bfa0745a33 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -407,7 +408,7 @@ index e3e1696e7f0e..423dc555093f 100644 -- 2.46.0 -From 8f69fe36b3d6052c7f41182041fc59ea84515066 Mon Sep 17 00:00:00 2001 +From 7279c37203fd8439ffc90a4f1c99eb27d8ff464d Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -448,7 +449,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.46.0 -From 457ccb4dad651a58bc24e4c49fcc95a81e3762bb Mon Sep 17 00:00:00 2001 +From 0d85a585d28cfb76cbc38e1ea8074cdacd326870 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -699,7 +700,7 @@ index 000000000000..35aeb5db89c8 -- 2.46.0 -From 281dcaef04abcc6a75b34c6f69f8f608b68912cf Mon Sep 17 00:00:00 2001 +From 611abcaeefb87f8987923ed404b8838ce57b21d6 Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -746,7 +747,7 @@ index 3df58eb3e882..81aff2d5d898 100644 -- 2.46.0 -From f1d09776b3c5026bfd4d035bbca5be3f8e41b247 Mon Sep 17 00:00:00 2001 +From bbe048ba6ea217036f92883be3d09f4fc247bdee Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.10/0014-amd-gpio.patch b/patches/6.10/0014-amd-gpio.patch index b1a3d0a01f..8dead83684 100644 --- a/patches/6.10/0014-amd-gpio.patch +++ b/patches/6.10/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 29121bd1e5b235572d56645abdb8f54a31bf476e Mon Sep 17 00:00:00 2001 +From 0b1d6ca9adc2621316781008a79b1e55672aa5ef Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 4bf82dbd2a6b..7a8cb090c656 100644 -- 2.46.0 -From f8d58835a76ce8ea016c0fcd75ddb93a95ca14c6 Mon Sep 17 00:00:00 2001 +From 008236d27babab8799a0fdd7c4c43a85df14c07f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.10/0015-rtc.patch b/patches/6.10/0015-rtc.patch index 78e2d0b991..43b9f9a4f8 100644 --- a/patches/6.10/0015-rtc.patch +++ b/patches/6.10/0015-rtc.patch @@ -1,4 +1,4 @@ -From 5c662b210790b2b297457de3e84274cc062b215e Mon Sep 17 00:00:00 2001 +From b12b4bf1a7d71d78f938b815ed59784efc46d932 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From 751c41737e4fdc31f2e0d7bc303a333e2dfdff66 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Sep 2024 04:12:52 +0200 Subject: [PATCH 056/236] Update Arch kernel to v6.10.10 --- pkg/arch/kernel/PKGBUILD | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index df19a6bfab..af13b9685a 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.10.5.arch1 +pkgver=6.10.10.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('985b89c2cfc91950562f29da121b1a38d9ae60afad2c29175f685067c8357408' +sha256sums=('e520738ac445054efc1931211ca12c39e6245ce8ece95808ad4e01904ed5be1a' '09bc22332affedcdf96cfa7b4ff3dcf1d087d1bde818b9929f5ad1102bc4f775' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '0c37af13f4e726b402ecdc134221c9622e158e6a04e466c90074101f044e5e0c' - '1c7a7bbfcf425575c76b02f06e23961a26ae3f948bf0cd44c99050fcc8ff091b' - '9586e84ba44bbc2f857e57e516f2a143f373e1346e4bb3902b2e800f703999c3' - 'fd032cd48c753ac0ce7d2569d846b2be8d6c2fe855123c8b81632a9466f349eb' - '99e93f1f941223d93997708205db90a09afcec9eb49535676e48d8d7961f42fa' - '496e6e88557cc353fe4a492e125bd14ca1234391052c75d024b20bcd0250edfb' - 'e03e0f0e4dc204cff1148a338646ecd560596f5e716c48a1bc9fa651839e59bc' - 'de44054877918c141c4cb365ce7054f06603fe32c2036141a16f0c618d032ad2' - 'bbc0f2ac46971de82c5870568eb3373fa9cc5ebb434a264ce6527ea4ae5beb05' - '0fbcb31344552dcc9a1c8036dabe6fb7de968c1ff8b8dc209cd9cd7ad06115fa' - 'bd87365738e35b866182db0380b1193abc55cc74b4682789d2449a6878a3d251' - 'be7601388ff83a32be59b9e00b14b69b9af78d4a11d5522b803482f3d2c3b5fc' - 'ac71b84c661ed5af8988d5ca85686cecf8797719bcf8787baff8753ea09faa79' - '49608d0a7096a3dfe7971ff99bd3746cdcd214ddb7b7d19b1fe97e3578f62bd2' - '9f90b7d26f23c66ac48fb012afb4703a5cdd652b6d1ca1c491ffdce7c89ebde0') + 'cb26323ca2d73b6180b468235a9a8611ca164b130d6c742a910b3d708fc88ea1' + '751d8242597e81eb45af9a5e04bea3b1206444aef004cb5f0b80de6f404b5f56' + '318c785b33790a4d5a44099d2cd8f961155b671935ac3bd519ced83a7e10b22c' + '48ac4f06b78bdc5e0b9d13c4366405accc42ad14b6623f9aeb6bf31569013b12' + 'ec3c09316a28e6046d6331f51def9f99c0cbf75f06abcf4fadbea5219b6e7d7d' + 'e6c01449502930ed924d2e127aa36240a1592a55398d6bb7a3654aa1cd3e9e45' + '8875c5688d18afe8923465f20f19a9e300125886103ce9ccc537446a265c74dd' + 'd8a69f59a70046415fe58ed6c2fadf1c6bed85c44fd739a4a692e2f3ae7c9cad' + 'edbfa3efeae6ac369dbdf922e77bddc9de2056055f27779baebb3a3c2a5f5760' + 'c9d0e7ff17855bc4a4e5e1a2aab2c50934f8ac7035766557aca1753a0cedee65' + '874fd44f469f6c7d45ed3cee48aa96e8853f0bec21508884f1d8cc838c925c70' + 'cf0a867b9859d5b1dee061defa89b2041571c6d003618c38ae7824b607731011' + '1ad798a5fb8c7a75101ea216cfb2613ef7bb44b8c717c99036dad6a1fbf2942e' + 'a6fbd34975461596de6936420dc68e93935745fd90d57d921a140d147f9b8575' + '0f3a51d4ab729072803fcac47878b7d9ce641a56f8fc02f1bfc337623e165283') export KBUILD_BUILD_HOST=archlinux From 4c17f3bab0daca975734147b5291ec27e4b4710f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Sep 2024 04:14:06 +0200 Subject: [PATCH 057/236] Update Debian kernel to v6.10.10 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 9d5a8014c3..6d91e8f96a 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.10.5" +KERNEL_VERSION="6.10.10" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 072135507d12fb544d908662637c9d81c1f3c44b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Sep 2024 04:14:46 +0200 Subject: [PATCH 058/236] Update Fedora kernels to v6.10.10 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 4fcce2d8c6..7dcdb8020d 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.10.5-0" +PACKAGE_TAG = "kernel-6.10.10-0" ## ## The release number of the modified kernel package. From bbf9548e3309fd226e729db53584fa0bf229a425 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 20 Sep 2024 22:07:23 +0200 Subject: [PATCH 059/236] Update v6.10 patches Changes: - Rebase onto v6.10.11 Links: - kernel: https://github.com/linux-surface/kernel/commit/4b6f46e5842a622a7e63d1d0822f0ac22019b040 --- patches/6.10/0001-secureboot.patch | 8 +- patches/6.10/0002-surface3-oemb.patch | 4 +- patches/6.10/0003-mwifiex.patch | 12 +- patches/6.10/0004-ath10k.patch | 4 +- patches/6.10/0005-ipts.patch | 12 +- patches/6.10/0006-ithc.patch | 8 +- patches/6.10/0007-surface-sam.patch | 280 +------------------ patches/6.10/0008-surface-sam-over-hid.patch | 8 +- patches/6.10/0009-surface-button.patch | 8 +- patches/6.10/0010-surface-typecover.patch | 38 +-- patches/6.10/0011-surface-shutdown.patch | 4 +- patches/6.10/0012-surface-gpe.patch | 4 +- patches/6.10/0013-cameras.patch | 44 +-- patches/6.10/0014-amd-gpio.patch | 8 +- patches/6.10/0015-rtc.patch | 4 +- 15 files changed, 87 insertions(+), 359 deletions(-) diff --git a/patches/6.10/0001-secureboot.patch b/patches/6.10/0001-secureboot.patch index 5f70268f23..a84252cca5 100644 --- a/patches/6.10/0001-secureboot.patch +++ b/patches/6.10/0001-secureboot.patch @@ -1,4 +1,4 @@ -From f042429d0ea3d440fa70f9c51c8197bb208f0a88 Mon Sep 17 00:00:00 2001 +From 2dd7c57b604b7cae49efcebc5fb6e46f7401a69b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.46.0 +2.46.1 -From db11088db25ece8759f2db44ae62b144575a3649 Mon Sep 17 00:00:00 2001 +From 8c63d9f68dff804be41fcf71b725a1e28c78118f Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -108,5 +108,5 @@ index 0a213f69a9e4..8e4f9dcc9f4c 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0002-surface3-oemb.patch b/patches/6.10/0002-surface3-oemb.patch index 75bf3ef7a6..4370ef10fb 100644 --- a/patches/6.10/0002-surface3-oemb.patch +++ b/patches/6.10/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 3b00df63072f59df6b111ad853b87094b3536442 Mon Sep 17 00:00:00 2001 +From 3d3aec0cd78fd07d406486dd140daa7baf1fba7c Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,5 +97,5 @@ index 5e2ec60e2954..207868c699f2 100644 }; -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0003-mwifiex.patch b/patches/6.10/0003-mwifiex.patch index 7f417177e2..97ba5fcfe9 100644 --- a/patches/6.10/0003-mwifiex.patch +++ b/patches/6.10/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 4ed887721124fdef2427143d1df5c56f42527b7e Mon Sep 17 00:00:00 2001 +From a50739a5e7b0ca9f6bca85606f2b9389a9dd6bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.46.0 +2.46.1 -From 894aa28465f66434a8c253eee50347f682c40117 Mon Sep 17 00:00:00 2001 +From 883ef69235ff8daa9653576dd6104460f60b7bde Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.46.0 +2.46.1 -From bca01a7cadbd3152491c45ae9d427478447cc483 Mon Sep 17 00:00:00 2001 +From 9e1720f0132e61bc6f738284080c6925941e1a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -396,5 +396,5 @@ index 0927f51867c2..3d3573829631 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0004-ath10k.patch b/patches/6.10/0004-ath10k.patch index c420e572bd..79ea37ce13 100644 --- a/patches/6.10/0004-ath10k.patch +++ b/patches/6.10/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 285063f8ccb7722b6eb27a6401fed87c86fd2e7f Mon Sep 17 00:00:00 2001 +From 68efac8fe5bd9af5e3c3e1d3cf7d9d2a3a5f4248 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index bdf0552cd1c3..e062cc687689 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0005-ipts.patch b/patches/6.10/0005-ipts.patch index 67e11af280..817b65d4db 100644 --- a/patches/6.10/0005-ipts.patch +++ b/patches/6.10/0005-ipts.patch @@ -1,4 +1,4 @@ -From 60cbae0f851d06cd4c356b29377ecbadfb08f874 Mon Sep 17 00:00:00 2001 +From 7e608ebdf188a298503111e503a4cc2fc3880f7c Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -35,9 +35,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.46.0 +2.46.1 -From 681a57dea0faeceb03b50752abbafb85341b981c Mon Sep 17 00:00:00 2001 +From 8b12cf7a1fe199057c7a39087d233f62fd4d6a93 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -142,9 +142,9 @@ index e9bea0305c26..6ee97bf7b6a9 100644 { if (risky_device(dev)) -- -2.46.0 +2.46.1 -From 56f5368c0bfde7b931fcb183cc779db625978f51 Mon Sep 17 00:00:00 2001 +From fd63fc042c6554c75134e4dab8e4a1d74c495d05 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3237,5 +3237,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0006-ithc.patch b/patches/6.10/0006-ithc.patch index d8afcc34a6..1bebd1a50d 100644 --- a/patches/6.10/0006-ithc.patch +++ b/patches/6.10/0006-ithc.patch @@ -1,4 +1,4 @@ -From 19b03c0a9c68f00487ed8c07163e819da9c63fdd Mon Sep 17 00:00:00 2001 +From dc65c76763207057a6797b0ef844c3f58e6a6e15 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index e4a70886678c..961a33b87c24 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.46.0 +2.46.1 -From 9f355143af2087aff4c4c1a6db46e6595e8ec5d4 Mon Sep 17 00:00:00 2001 +From c3ddc02f7b0e27c09233022d7bbfd6b72ca12d2e Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -2767,5 +2767,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0007-surface-sam.patch b/patches/6.10/0007-surface-sam.patch index 13ebbe5b50..51f60eb415 100644 --- a/patches/6.10/0007-surface-sam.patch +++ b/patches/6.10/0007-surface-sam.patch @@ -1,164 +1,4 @@ -From 1c0c81136657ad8656e5d713d0d8282d70413e53 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 22 Oct 2023 14:57:11 +0200 -Subject: [PATCH] platform/surface: aggregator_registry: Add support for - Surface Laptop Go 3 - -Add SAM client device nodes for the Surface Laptop Go 3. It seems to use -the same SAM client devices as the Surface Laptop Go 1 and 2, so re-use -their node group. - -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 1c4d74db08c9..f826489dc69d 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -395,6 +395,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { - /* Surface Laptop Go 2 */ - { "MSHW0290", (unsigned long)ssam_node_group_slg1 }, - -+ /* Surface Laptop Go 3 */ -+ { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, -+ - /* Surface Laptop Studio */ - { "MSHW0123", (unsigned long)ssam_node_group_sls }, - --- -2.46.0 - -From 74e058609a1229cfd478690ae2ad0fbb209ee6ed Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Mon, 20 Nov 2023 19:47:00 +0100 -Subject: [PATCH] platform/surface: aggregator_registry: Add support for - Surface Laptop Studio 2 - -Add SAM client device nodes for the Surface Laptop Studio 2 (SLS2). The -SLS2 is quite similar to the SLS1, but it does not provide the touchpad -as a SAM-HID device. Therefore, add a new node group for the SLS2 and -update the comments accordingly - -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - .../surface/surface_aggregator_registry.c | 25 ++++++++++++++++--- - 1 file changed, 21 insertions(+), 4 deletions(-) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index f826489dc69d..ef59a7b66667 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -273,8 +273,8 @@ static const struct software_node *ssam_node_group_sl5[] = { - NULL, - }; - --/* Devices for Surface Laptop Studio. */ --static const struct software_node *ssam_node_group_sls[] = { -+/* Devices for Surface Laptop Studio 1. */ -+static const struct software_node *ssam_node_group_sls1[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -@@ -289,6 +289,20 @@ static const struct software_node *ssam_node_group_sls[] = { - NULL, - }; - -+/* Devices for Surface Laptop Studio 2. */ -+static const struct software_node *ssam_node_group_sls2[] = { -+ &ssam_node_root, -+ &ssam_node_bat_ac, -+ &ssam_node_bat_main, -+ &ssam_node_tmp_pprof, -+ &ssam_node_pos_tablet_switch, -+ &ssam_node_hid_sam_keyboard, -+ &ssam_node_hid_sam_penstash, -+ &ssam_node_hid_sam_sensors, -+ &ssam_node_hid_sam_ucm_ucsi, -+ NULL, -+}; -+ - /* Devices for Surface Laptop Go. */ - static const struct software_node *ssam_node_group_slg1[] = { - &ssam_node_root, -@@ -398,8 +412,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { - /* Surface Laptop Go 3 */ - { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, - -- /* Surface Laptop Studio */ -- { "MSHW0123", (unsigned long)ssam_node_group_sls }, -+ /* Surface Laptop Studio 1 */ -+ { "MSHW0123", (unsigned long)ssam_node_group_sls1 }, -+ -+ /* Surface Laptop Studio 2 */ -+ { "MSHW0360", (unsigned long)ssam_node_group_sls2 }, - - { }, - }; --- -2.46.0 - -From 61ed1a703286c45a6f9de31053a8041e7e54cd4d Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 9 Jun 2024 20:05:57 +0200 -Subject: [PATCH] platform/surface: aggregator_registry: Add support for - Surface Laptop 6 - -Add SAM client device nodes for the Surface Laptop Studio 6 (SL6). The -SL6 is similar to the SL5, with the typical battery/AC, platform -profile, and HID nodes. It also has support for the newly supported fan -interface. - -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - .../surface/surface_aggregator_registry.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index ef59a7b66667..a20ccf49731c 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -273,6 +273,22 @@ static const struct software_node *ssam_node_group_sl5[] = { - NULL, - }; - -+/* Devices for Surface Laptop 6. */ -+static const struct software_node *ssam_node_group_sl6[] = { -+ &ssam_node_root, -+ &ssam_node_bat_ac, -+ &ssam_node_bat_main, -+ &ssam_node_tmp_perf_profile_with_fan, -+ &ssam_node_tmp_sensors, -+ &ssam_node_fan_speed, -+ &ssam_node_hid_main_keyboard, -+ &ssam_node_hid_main_touchpad, -+ &ssam_node_hid_main_iid5, -+ &ssam_node_hid_sam_sensors, -+ &ssam_node_hid_sam_ucm_ucsi, -+ NULL, -+}; -+ - /* Devices for Surface Laptop Studio 1. */ - static const struct software_node *ssam_node_group_sls1[] = { - &ssam_node_root, -@@ -403,6 +419,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { - /* Surface Laptop 5 */ - { "MSHW0350", (unsigned long)ssam_node_group_sl5 }, - -+ /* Surface Laptop 6 */ -+ { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, -+ - /* Surface Laptop Go 1 */ - { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, - --- -2.46.0 - -From be2709e2a0ddebba3887d730a2e61b7bec2a06f2 Mon Sep 17 00:00:00 2001 +From 3e6733db885b3a91339039897cbf0f3e05cda2a5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -384,9 +224,9 @@ index 000000000000..48c3e826713f +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.46.0 +2.46.1 -From 15ba0027e4d72f580255f8776ee251c94f81cab1 Mon Sep 17 00:00:00 2001 +From 3e4479ac556ff21b45485822edb0980bbb27fdba Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -579,117 +419,5 @@ index 48c3e826713f..4c08926139db 100644 "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, NULL); -- -2.46.0 - -From b80e50b1a90e22d3a200b085cac567905e56543c Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Mon, 10 Jun 2024 21:47:47 +0200 -Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal - sensor support for Surface Laptop 5 - -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index a20ccf49731c..2b20c74bbe6d 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -265,7 +265,9 @@ static const struct software_node *ssam_node_group_sl5[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_perf_profile, -+ &ssam_node_tmp_perf_profile_with_fan, -+ &ssam_node_tmp_sensors, -+ &ssam_node_fan_speed, - &ssam_node_hid_main_keyboard, - &ssam_node_hid_main_touchpad, - &ssam_node_hid_main_iid5, --- -2.46.0 - -From 06973bc3db29f5d009d4de6298e0496490c811ee Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Mon, 10 Jun 2024 21:48:02 +0200 -Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal - sensor support for Surface Laptop Studio 2 - -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 2b20c74bbe6d..1e7e7ebeb074 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -312,7 +312,9 @@ static const struct software_node *ssam_node_group_sls2[] = { - &ssam_node_root, - &ssam_node_bat_ac, - &ssam_node_bat_main, -- &ssam_node_tmp_pprof, -+ &ssam_node_tmp_perf_profile_with_fan, -+ &ssam_node_tmp_sensors, -+ &ssam_node_fan_speed, - &ssam_node_pos_tablet_switch, - &ssam_node_hid_sam_keyboard, - &ssam_node_hid_sam_penstash, --- -2.46.0 - -From 01cab9f250e8dc4b6a2e784467487f7eb03e7afe Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Fri, 28 Jun 2024 22:31:37 +0200 -Subject: [PATCH] platform/surface: aggregator_registry: Add Support for - Surface Pro 10 - -Patchset: surface-sam ---- - .../surface/surface_aggregator_registry.c | 22 +++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 1e7e7ebeb074..ec9eb4d375b9 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -377,6 +377,25 @@ static const struct software_node *ssam_node_group_sp9[] = { - NULL, - }; - -+/* Devices for Surface Pro 10 */ -+static const struct software_node *ssam_node_group_sp10[] = { -+ &ssam_node_root, -+ &ssam_node_hub_kip, -+ &ssam_node_bat_ac, -+ &ssam_node_bat_main, -+ &ssam_node_tmp_perf_profile_with_fan, -+ &ssam_node_tmp_sensors, -+ &ssam_node_fan_speed, -+ &ssam_node_pos_tablet_switch, -+ &ssam_node_hid_kip_keyboard, -+ &ssam_node_hid_kip_penstash, -+ &ssam_node_hid_kip_touchpad, -+ &ssam_node_hid_kip_fwupd, -+ &ssam_node_hid_sam_sensors, -+ &ssam_node_hid_sam_ucm_ucsi, -+ NULL, -+}; -+ - - /* -- SSAM platform/meta-hub driver. ---------------------------------------- */ - -@@ -399,6 +418,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { - /* Surface Pro 9 */ - { "MSHW0343", (unsigned long)ssam_node_group_sp9 }, - -+ /* Surface Pro 10 */ -+ { "MSHW0510", (unsigned long)ssam_node_group_sp10 }, -+ - /* Surface Book 2 */ - { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, - --- -2.46.0 +2.46.1 diff --git a/patches/6.10/0008-surface-sam-over-hid.patch b/patches/6.10/0008-surface-sam-over-hid.patch index 43c028ab40..2916ab4a70 100644 --- a/patches/6.10/0008-surface-sam-over-hid.patch +++ b/patches/6.10/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 6e7285d272dd52c42f6e2f17264a88abe8460a99 Mon Sep 17 00:00:00 2001 +From 134830c02674d93c2433bb898de34d1b84467f86 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index 14ae0cfc325e..6197c5252d2a 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.46.0 +2.46.1 -From 0ce0983a58d19778a010c55e6ca16e344a28b4a1 Mon Sep 17 00:00:00 2001 +From 61af2c864646d5582463f9e5fbf06a96e0c4300d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0009-surface-button.patch b/patches/6.10/0009-surface-button.patch index 7a8f8aceb3..4c84ec181e 100644 --- a/patches/6.10/0009-surface-button.patch +++ b/patches/6.10/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 81f45954e36d6ce9e5f217bde8149cb3f5d1ff6c Mon Sep 17 00:00:00 2001 +From 02f4deefe4c0ab63cd6771198cd05d5798fcc80f Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index f6d060377d18..b8603f74eb28 100644 /* -- -2.46.0 +2.46.1 -From 94aa734ec2fd6eef10ae5155c1ba2e6d063f73f8 Mon Sep 17 00:00:00 2001 +From fbdda31b4a3ce2a7113fa831056830b6b46cf0df Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0010-surface-typecover.patch b/patches/6.10/0010-surface-typecover.patch index 7cd7e1ebe7..72d6d86a56 100644 --- a/patches/6.10/0010-surface-typecover.patch +++ b/patches/6.10/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 1525b314caae3999007352990890172d87358d8c Mon Sep 17 00:00:00 2001 +From edc26a9d993aca624b164989945d6bbcc5c7a856 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -37,9 +37,9 @@ index 13171454f959..a83beefd25f3 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.46.0 +2.46.1 -From 0e0e42f91887b34bb83cc84d29228b7464001558 Mon Sep 17 00:00:00 2001 +From 43bac5cac64c45b423509196acdb2261c3f0a7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 56fc78841f24..a266449065a0 100644 +index 99812c0f830b..0b3b51e37149 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -147,7 +147,7 @@ index 56fc78841f24..a266449065a0 100644 { } }; -@@ -1720,6 +1740,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1744,6 +1764,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index 56fc78841f24..a266449065a0 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1743,6 +1826,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1767,6 +1850,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index 56fc78841f24..a266449065a0 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1781,15 +1867,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1805,15 +1891,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -249,7 +249,7 @@ index 56fc78841f24..a266449065a0 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1839,6 +1929,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1863,6 +1953,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -257,7 +257,7 @@ index 56fc78841f24..a266449065a0 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2235,6 +2326,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2267,6 +2358,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -270,9 +270,9 @@ index 56fc78841f24..a266449065a0 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.46.0 +2.46.1 -From 393718e523dac04097a037778d4896e88b4a0d96 Mon Sep 17 00:00:00 2001 +From 41478ba3be0680c18610cb66f5344abadff1b82d Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -301,7 +301,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index a266449065a0..060c706e936a 100644 +index 0b3b51e37149..481b97dce830 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -411,7 +411,7 @@ index a266449065a0..060c706e936a 100644 return 0; } -@@ -1610,6 +1656,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1634,6 +1680,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -454,7 +454,7 @@ index a266449065a0..060c706e936a 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1658,6 +1740,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1682,6 +1764,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -468,7 +468,7 @@ index a266449065a0..060c706e936a 100644 default: suffix = "UNKNOWN"; break; -@@ -1740,30 +1829,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1764,30 +1853,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -499,7 +499,7 @@ index a266449065a0..060c706e936a 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1772,8 +1837,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1796,8 +1861,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -511,7 +511,7 @@ index a266449065a0..060c706e936a 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -1907,13 +1973,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -1931,13 +1997,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -536,7 +536,7 @@ index a266449065a0..060c706e936a 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1922,12 +1999,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -1946,12 +2023,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); @@ -569,5 +569,5 @@ index a266449065a0..060c706e936a 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0011-surface-shutdown.patch b/patches/6.10/0011-surface-shutdown.patch index f8cebf0583..28a8ca6cad 100644 --- a/patches/6.10/0011-surface-shutdown.patch +++ b/patches/6.10/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 85df3c0422688b4010a1cd9079511b1a0e2b38a8 Mon Sep 17 00:00:00 2001 +From fe6c6b6e8d581aeca114902ec5f962a44a0ee3ff Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -93,5 +93,5 @@ index cafc5ab1cbcb..64bb5aca2c13 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0012-surface-gpe.patch b/patches/6.10/0012-surface-gpe.patch index a6da37aa09..8a66e178be 100644 --- a/patches/6.10/0012-surface-gpe.patch +++ b/patches/6.10/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From e17a29ddcf58b4e9b43234c8ad4b6a73fddbe0d4 Mon Sep 17 00:00:00 2001 +From d0443743ccc9c4d76192f7bbf0152990e461945e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0013-cameras.patch b/patches/6.10/0013-cameras.patch index 9a6b91e2de..54620c7313 100644 --- a/patches/6.10/0013-cameras.patch +++ b/patches/6.10/0013-cameras.patch @@ -1,4 +1,4 @@ -From 6a5e5f7496e5e5a86dd43da8bdf955fb2cb330e5 Mon Sep 17 00:00:00 2001 +From e7b32369a9dc01221dc44a1250c425d8ebc9b28b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index cdc5a74092c7..e3a16c14a29e 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.46.0 +2.46.1 -From 839e164bf1650a36b9c5c955035e900cdea017da Mon Sep 17 00:00:00 2001 +From aa71d469b9000984bfbd4ee4f596517db89bcb46 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -182,9 +182,9 @@ index 6ee97bf7b6a9..a1f86bde277a 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.46.0 +2.46.1 -From b9a1edc6bbf4fa65e14a530bf353fea2838cafc6 Mon Sep 17 00:00:00 2001 +From fb1981ea8427c311f08860ddbb2ea1b7e1ddd313 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 1e107fd49f82..e3e1696e7f0e 100644 return 0; -- -2.46.0 +2.46.1 -From 139109dc8f358284091d856e8c8a96117a359d8e Mon Sep 17 00:00:00 2001 +From ae05619486ea72603af63628e7f7a0c3b4f045ac Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -275,9 +275,9 @@ index 07b302e09340..baad1e50ca81 100644 agpio, func, polarity); if (ret) -- -2.46.0 +2.46.1 -From 8d89dfb5a37b9bf23909612e70cded7e0e6713fe Mon Sep 17 00:00:00 2001 +From 7066acd9423a7eecc94d22397095e04f4a47aba8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -314,9 +314,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.46.0 +2.46.1 -From b528a28460ee1cd74d6a5c9fd156cd3275124610 Mon Sep 17 00:00:00 2001 +From 9feb537c1c69e0d01ad3ed713959fcf371dc2db6 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -365,9 +365,9 @@ index 89c7192148df..44eca113e772 100644 if (ret < 0) goto out_cleanup; -- -2.46.0 +2.46.1 -From a906d692dab6a3d74a30e3d92b8419bfa0745a33 Mon Sep 17 00:00:00 2001 +From 580ca92681c7c6bafa132b81043fbd0857b5da6b Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -406,9 +406,9 @@ index e3e1696e7f0e..423dc555093f 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.46.0 +2.46.1 -From 7279c37203fd8439ffc90a4f1c99eb27d8ff464d Mon Sep 17 00:00:00 2001 +From ef863c4385da78967765505ccd3702371a32d70e Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -447,9 +447,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.46.0 +2.46.1 -From 0d85a585d28cfb76cbc38e1ea8074cdacd326870 Mon Sep 17 00:00:00 2001 +From e81fa0ec83149cf15d779fea0ba7435f8fd28898 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -698,9 +698,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.46.0 +2.46.1 -From 611abcaeefb87f8987923ed404b8838ce57b21d6 Mon Sep 17 00:00:00 2001 +From afce9fb83bf7355d5ceb4a6958023dd07e00cfdf Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -745,9 +745,9 @@ index 3df58eb3e882..81aff2d5d898 100644 r = imgu_s_stream(imgu, false); if (!r) -- -2.46.0 +2.46.1 -From bbe048ba6ea217036f92883be3d09f4fc247bdee Mon Sep 17 00:00:00 2001 +From 10cc9e54fa6067a0c08dc4f2c0f5bf029e3a4ed1 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -777,5 +777,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0014-amd-gpio.patch b/patches/6.10/0014-amd-gpio.patch index 8dead83684..21d3ccb2d8 100644 --- a/patches/6.10/0014-amd-gpio.patch +++ b/patches/6.10/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 0b1d6ca9adc2621316781008a79b1e55672aa5ef Mon Sep 17 00:00:00 2001 +From 04f1ce03393e660c6275004e0ccda0f1e4481f8b Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 4bf82dbd2a6b..7a8cb090c656 100644 mp_config_acpi_legacy_irqs(); -- -2.46.0 +2.46.1 -From 008236d27babab8799a0fdd7c4c43a85df14c07f Mon Sep 17 00:00:00 2001 +From a05e3240a282702699117da0e657a46bc960a944 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 7a8cb090c656..0faafc323e67 100644 }; -- -2.46.0 +2.46.1 diff --git a/patches/6.10/0015-rtc.patch b/patches/6.10/0015-rtc.patch index 43b9f9a4f8..38ca064ee6 100644 --- a/patches/6.10/0015-rtc.patch +++ b/patches/6.10/0015-rtc.patch @@ -1,4 +1,4 @@ -From b12b4bf1a7d71d78f938b815ed59784efc46d932 Mon Sep 17 00:00:00 2001 +From 4e5c87c48625f80729705e6ca756b289dace0452 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 1d670dbe4d1d..71c9e375ca1c 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.46.0 +2.46.1 From c863f435d28498fb103d28616ba7d49e30a03d88 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 20 Sep 2024 22:08:14 +0200 Subject: [PATCH 060/236] Add patches for 6.11 Derived from latest 6.10 patches Links: - kernel: https://github.com/linux-surface/kernel/commit/a45bcc81c1b1a9922d759de30798e9f3bd89f1ac - tree-devel: https://github.com/linux-surface/kernel/commits/v6.11-surface-devel - tree-patches: https://github.com/linux-surface/kernel/commits/v6.11-surface --- configs/surface-6.11.config | 81 + patches/6.11/0001-secureboot.patch | 112 + patches/6.11/0002-surface3-oemb.patch | 101 + patches/6.11/0003-mwifiex.patch | 400 +++ patches/6.11/0004-ath10k.patch | 120 + patches/6.11/0005-ipts.patch | 3241 ++++++++++++++++++ patches/6.11/0006-ithc.patch | 2771 +++++++++++++++ patches/6.11/0007-surface-sam.patch | 423 +++ patches/6.11/0008-surface-sam-over-hid.patch | 308 ++ patches/6.11/0009-surface-button.patch | 149 + patches/6.11/0010-surface-typecover.patch | 573 ++++ patches/6.11/0011-surface-shutdown.patch | 97 + patches/6.11/0012-surface-gpe.patch | 51 + patches/6.11/0013-cameras.patch | 781 +++++ patches/6.11/0014-amd-gpio.patch | 109 + patches/6.11/0015-rtc.patch | 110 + 16 files changed, 9427 insertions(+) create mode 100644 configs/surface-6.11.config create mode 100644 patches/6.11/0001-secureboot.patch create mode 100644 patches/6.11/0002-surface3-oemb.patch create mode 100644 patches/6.11/0003-mwifiex.patch create mode 100644 patches/6.11/0004-ath10k.patch create mode 100644 patches/6.11/0005-ipts.patch create mode 100644 patches/6.11/0006-ithc.patch create mode 100644 patches/6.11/0007-surface-sam.patch create mode 100644 patches/6.11/0008-surface-sam-over-hid.patch create mode 100644 patches/6.11/0009-surface-button.patch create mode 100644 patches/6.11/0010-surface-typecover.patch create mode 100644 patches/6.11/0011-surface-shutdown.patch create mode 100644 patches/6.11/0012-surface-gpe.patch create mode 100644 patches/6.11/0013-cameras.patch create mode 100644 patches/6.11/0014-amd-gpio.patch create mode 100644 patches/6.11/0015-rtc.patch diff --git a/configs/surface-6.11.config b/configs/surface-6.11.config new file mode 100644 index 0000000000..05628a9957 --- /dev/null +++ b/configs/surface-6.11.config @@ -0,0 +1,81 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m diff --git a/patches/6.11/0001-secureboot.patch b/patches/6.11/0001-secureboot.patch new file mode 100644 index 0000000000..68c0b18200 --- /dev/null +++ b/patches/6.11/0001-secureboot.patch @@ -0,0 +1,112 @@ +From 3072491a57e495f0c1cea7d177f23b7e1b2dce4f Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.46.1 + +From 5c2e6c9e2424f940b98ac772b9e8c6bae07563c9 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 09126bb8cc9f..d4203d40146e 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3020,6 +3020,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 0a213f69a9e4..8e4f9dcc9f4c 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1422,6 +1423,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1480,3 +1487,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.46.1 + diff --git a/patches/6.11/0002-surface3-oemb.patch b/patches/6.11/0002-surface3-oemb.patch new file mode 100644 index 0000000000..2e36bc27da --- /dev/null +++ b/patches/6.11/0002-surface3-oemb.patch @@ -0,0 +1,101 @@ +From 5e2a56c28a75458faee96311074a886d18df278e Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-oemb +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index c15ed7a12784..1ec8edb5aafa 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.46.1 + diff --git a/patches/6.11/0003-mwifiex.patch b/patches/6.11/0003-mwifiex.patch new file mode 100644 index 0000000000..ba5d9e6d4a --- /dev/null +++ b/patches/6.11/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From d3dce7daa7c9b02fffc26ab4b001dd28bacc0354 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.46.1 + +From 9769338807b783cee28ff7bccbaa0e60c684be9f Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.46.1 + +From f9801752d406cd308af5286c21bb27d946d3e9c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 51d9d4532dda..e62c565ebc6d 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -468,6 +469,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -3856,6 +3858,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.46.1 + diff --git a/patches/6.11/0004-ath10k.patch b/patches/6.11/0004-ath10k.patch new file mode 100644 index 0000000000..77ff702850 --- /dev/null +++ b/patches/6.11/0004-ath10k.patch @@ -0,0 +1,120 @@ +From 137690d1fd93f0c5f723f1734e2b8db6709f806e Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index b3294287bce1..2936fdae823c 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.46.1 + diff --git a/patches/6.11/0005-ipts.patch b/patches/6.11/0005-ipts.patch new file mode 100644 index 0000000000..62533e4f68 --- /dev/null +++ b/patches/6.11/0005-ipts.patch @@ -0,0 +1,3241 @@ +From 349269d5e90409c3dd12e022da4771c6a66752b6 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6589635f8ba3..a1df48a434e2 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.46.1 + +From 9c052968302b202812f519f38839dd00d3621795 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 4aa070cf56e7..5df658b9811b 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -40,6 +40,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -217,12 +222,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -2156,6 +2163,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2456,6 +2466,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + ret = si_domain_init(hw_pass_through); +@@ -4699,6 +4712,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4734,6 +4759,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.46.1 + +From 4d098196ff771e07ce301632377779c94dfa7cb4 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 08446c89eff6..ccddfba86004 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1367,4 +1367,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + + source "drivers/hid/surface-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index e40f1ddebbb7..bdb17cffca2f 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -169,3 +169,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.46.1 + diff --git a/patches/6.11/0006-ithc.patch b/patches/6.11/0006-ithc.patch new file mode 100644 index 0000000000..6a05435705 --- /dev/null +++ b/patches/6.11/0006-ithc.patch @@ -0,0 +1,2771 @@ +From 153d9fcfbe1cd5765470d42ae7aa82825dc9ffc3 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index e090ca07364b..e575193615bf 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.46.1 + +From e3fd5a2f58e174fab58d777ad43a2fb378e58ce9 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index ccddfba86004..8e2ea8175bfb 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1369,4 +1369,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index bdb17cffca2f..8987177f8b81 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -171,3 +171,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.46.1 + diff --git a/patches/6.11/0007-surface-sam.patch b/patches/6.11/0007-surface-sam.patch new file mode 100644 index 0000000000..def4813d76 --- /dev/null +++ b/patches/6.11/0007-surface-sam.patch @@ -0,0 +1,423 @@ +From 046b4dd2291ee2e379f529037eab24d6b0cee56e Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 30 Dec 2023 18:07:54 +0100 +Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator + Module + +Some of the newer Microsoft Surface devices (such as the Surface Book +3 and Pro 9) have thermal sensors connected via the Surface Aggregator +Module (the embedded controller on those devices). Add a basic driver +to read out the temperature values of those sensors. + +Link: https://github.com/linux-surface/surface-aggregator-module/issues/59 +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/hwmon/Kconfig | 10 +++ + drivers/hwmon/Makefile | 1 + + drivers/hwmon/surface_temp.c | 165 +++++++++++++++++++++++++++++++++++ + 3 files changed, 176 insertions(+) + create mode 100644 drivers/hwmon/surface_temp.c + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index b60fe2e58ad6..70c6385f0ed6 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -2080,6 +2080,16 @@ config SENSORS_SURFACE_FAN + + Select M or Y here, if you want to be able to read the fan's speed. + ++config SENSORS_SURFACE_TEMP ++ tristate "Microsoft Surface Thermal Sensor Driver" ++ depends on SURFACE_AGGREGATOR ++ help ++ Driver for monitoring thermal sensors connected via the Surface ++ Aggregator Module (embedded controller) on Microsoft Surface devices. ++ ++ This driver can also be built as a module. If so, the module ++ will be called surface_temp. ++ + config SENSORS_ADC128D818 + tristate "Texas Instruments ADC128D818" + depends on I2C +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index b1c7056c37db..3ce8d6a9202e 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -209,6 +209,7 @@ obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o + obj-$(CONFIG_SENSORS_SPD5118) += spd5118.o + obj-$(CONFIG_SENSORS_STTS751) += stts751.o + obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o ++obj-$(CONFIG_SENSORS_SURFACE_TEMP)+= surface_temp.o + obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o + obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o + obj-$(CONFIG_SENSORS_TC74) += tc74.o +diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c +new file mode 100644 +index 000000000000..48c3e826713f +--- /dev/null ++++ b/drivers/hwmon/surface_temp.c +@@ -0,0 +1,165 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Thermal sensor subsystem driver for Surface System Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2022-2023 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++/* -- SAM interface. -------------------------------------------------------- */ ++ ++SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x04, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x01, ++}); ++ ++static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors) ++{ ++ __le16 sensors_le; ++ int status; ++ ++ status = __ssam_tmp_get_available_sensors(sdev, &sensors_le); ++ if (status) ++ return status; ++ ++ *sensors = le16_to_cpu(sensors_le); ++ return 0; ++} ++ ++static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temperature) ++{ ++ __le16 temp_le; ++ int status; ++ ++ status = __ssam_tmp_get_temperature(sdev->ctrl, sdev->uid.target, iid, &temp_le); ++ if (status) ++ return status; ++ ++ /* Convert 1/10 °K to 1/1000 °C */ ++ *temperature = (le16_to_cpu(temp_le) - 2731) * 100L; ++ return 0; ++} ++ ++ ++/* -- Driver.---------------------------------------------------------------- */ ++ ++struct ssam_temp { ++ struct ssam_device *sdev; ++ s16 sensors; ++}; ++ ++static umode_t ssam_temp_hwmon_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct ssam_temp *ssam_temp = data; ++ ++ if (!(ssam_temp->sensors & BIT(channel))) ++ return 0; ++ ++ return 0444; ++} ++ ++static int ssam_temp_hwmon_read(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, long *value) ++{ ++ const struct ssam_temp *ssam_temp = dev_get_drvdata(dev); ++ ++ return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value); ++} ++ ++static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = { ++ HWMON_CHANNEL_INFO(chip, ++ HWMON_C_REGISTER_TZ), ++ /* We have at most 16 thermal sensor channels. */ ++ HWMON_CHANNEL_INFO(temp, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT, ++ HWMON_T_INPUT), ++ NULL ++}; ++ ++static const struct hwmon_ops ssam_temp_hwmon_ops = { ++ .is_visible = ssam_temp_hwmon_is_visible, ++ .read = ssam_temp_hwmon_read, ++}; ++ ++static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = { ++ .ops = &ssam_temp_hwmon_ops, ++ .info = ssam_temp_hwmon_info, ++}; ++ ++static int ssam_temp_probe(struct ssam_device *sdev) ++{ ++ struct ssam_temp *ssam_temp; ++ struct device *hwmon_dev; ++ s16 sensors; ++ int status; ++ ++ status = ssam_tmp_get_available_sensors(sdev, &sensors); ++ if (status) ++ return status; ++ ++ ssam_temp = devm_kzalloc(&sdev->dev, sizeof(*ssam_temp), GFP_KERNEL); ++ if (!ssam_temp) ++ return -ENOMEM; ++ ++ ssam_temp->sdev = sdev; ++ ssam_temp->sensors = sensors; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev, ++ "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, ++ NULL); ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ return 0; ++} ++ ++static const struct ssam_device_id ssam_temp_match[] = { ++ { SSAM_SDEV(TMP, SAM, 0x00, 0x02) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, ssam_temp_match); ++ ++static struct ssam_device_driver ssam_temp = { ++ .probe = ssam_temp_probe, ++ .match_table = ssam_temp_match, ++ .driver = { ++ .name = "surface_temp", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(ssam_temp); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.46.1 + +From e8afedc65f5b36c2e2845e7b5848750785512817 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 30 Dec 2023 18:12:23 +0100 +Subject: [PATCH] hwmon: surface_temp: Add support for sensor names + +The thermal subsystem of the Surface Aggregator Module allows us to +query the names of the respective thermal sensors. Forward those to +userspace. + +Signed-off-by: Ivor Wanders +Co-Developed-by: Maximilian Luz +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/hwmon/surface_temp.c | 113 +++++++++++++++++++++++++++++------ + 1 file changed, 96 insertions(+), 17 deletions(-) + +diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c +index 48c3e826713f..4c08926139db 100644 +--- a/drivers/hwmon/surface_temp.c ++++ b/drivers/hwmon/surface_temp.c +@@ -17,6 +17,27 @@ + + /* -- SAM interface. -------------------------------------------------------- */ + ++/* ++ * Available sensors are indicated by a 16-bit bitfield, where a 1 marks the ++ * presence of a sensor. So we have at most 16 possible sensors/channels. ++ */ ++#define SSAM_TMP_SENSOR_MAX_COUNT 16 ++ ++/* ++ * All names observed so far are 6 characters long, but there's only ++ * zeros after the name, so perhaps they can be longer. This number reflects ++ * the maximum zero-padded space observed in the returned buffer. ++ */ ++#define SSAM_TMP_SENSOR_NAME_LENGTH 18 ++ ++struct ssam_tmp_get_name_rsp { ++ __le16 unknown1; ++ char unknown2; ++ char name[SSAM_TMP_SENSOR_NAME_LENGTH]; ++} __packed; ++ ++static_assert(sizeof(struct ssam_tmp_get_name_rsp) == 21); ++ + SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_get_available_sensors, __le16, { + .target_category = SSAM_SSH_TC_TMP, + .command_id = 0x04, +@@ -27,6 +48,11 @@ SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_temperature, __le16, { + .command_id = 0x01, + }); + ++SSAM_DEFINE_SYNC_REQUEST_MD_R(__ssam_tmp_get_name, struct ssam_tmp_get_name_rsp, { ++ .target_category = SSAM_SSH_TC_TMP, ++ .command_id = 0x0e, ++}); ++ + static int ssam_tmp_get_available_sensors(struct ssam_device *sdev, s16 *sensors) + { + __le16 sensors_le; +@@ -54,12 +80,37 @@ static int ssam_tmp_get_temperature(struct ssam_device *sdev, u8 iid, long *temp + return 0; + } + ++static int ssam_tmp_get_name(struct ssam_device *sdev, u8 iid, char *buf, size_t buf_len) ++{ ++ struct ssam_tmp_get_name_rsp name_rsp; ++ int status; ++ ++ status = __ssam_tmp_get_name(sdev->ctrl, sdev->uid.target, iid, &name_rsp); ++ if (status) ++ return status; ++ ++ /* ++ * This should not fail unless the name in the returned struct is not ++ * null-terminated or someone changed something in the struct ++ * definitions above, since our buffer and struct have the same ++ * capacity by design. So if this fails blow this up with a warning. ++ * Since the more likely cause is that the returned string isn't ++ * null-terminated, we might have received garbage (as opposed to just ++ * an incomplete string), so also fail the function. ++ */ ++ status = strscpy(buf, name_rsp.name, buf_len); ++ WARN_ON(status < 0); ++ ++ return status < 0 ? status : 0; ++} ++ + + /* -- Driver.---------------------------------------------------------------- */ + + struct ssam_temp { + struct ssam_device *sdev; + s16 sensors; ++ char names[SSAM_TMP_SENSOR_MAX_COUNT][SSAM_TMP_SENSOR_NAME_LENGTH]; + }; + + static umode_t ssam_temp_hwmon_is_visible(const void *data, +@@ -83,33 +134,47 @@ static int ssam_temp_hwmon_read(struct device *dev, + return ssam_tmp_get_temperature(ssam_temp->sdev, channel + 1, value); + } + ++static int ssam_temp_hwmon_read_string(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, const char **str) ++{ ++ const struct ssam_temp *ssam_temp = dev_get_drvdata(dev); ++ ++ *str = ssam_temp->names[channel]; ++ return 0; ++} ++ + static const struct hwmon_channel_info * const ssam_temp_hwmon_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_REGISTER_TZ), +- /* We have at most 16 thermal sensor channels. */ ++ /* ++ * We have at most SSAM_TMP_SENSOR_MAX_COUNT = 16 thermal sensor ++ * channels. ++ */ + HWMON_CHANNEL_INFO(temp, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT, +- HWMON_T_INPUT), ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL), + NULL + }; + + static const struct hwmon_ops ssam_temp_hwmon_ops = { + .is_visible = ssam_temp_hwmon_is_visible, + .read = ssam_temp_hwmon_read, ++ .read_string = ssam_temp_hwmon_read_string, + }; + + static const struct hwmon_chip_info ssam_temp_hwmon_chip_info = { +@@ -122,6 +187,7 @@ static int ssam_temp_probe(struct ssam_device *sdev) + struct ssam_temp *ssam_temp; + struct device *hwmon_dev; + s16 sensors; ++ int channel; + int status; + + status = ssam_tmp_get_available_sensors(sdev, &sensors); +@@ -135,6 +201,19 @@ static int ssam_temp_probe(struct ssam_device *sdev) + ssam_temp->sdev = sdev; + ssam_temp->sensors = sensors; + ++ /* Retrieve the name for each available sensor. */ ++ for (channel = 0; channel < SSAM_TMP_SENSOR_MAX_COUNT; channel++) ++ { ++ if (!(sensors & BIT(channel))) ++ continue; ++ ++ status = ssam_tmp_get_name(sdev, channel + 1, ++ ssam_temp->names[channel], ++ SSAM_TMP_SENSOR_NAME_LENGTH); ++ if (status) ++ return status; ++ } ++ + hwmon_dev = devm_hwmon_device_register_with_info(&sdev->dev, + "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, + NULL); +-- +2.46.1 + diff --git a/patches/6.11/0008-surface-sam-over-hid.patch b/patches/6.11/0008-surface-sam-over-hid.patch new file mode 100644 index 0000000000..c4ede3bf82 --- /dev/null +++ b/patches/6.11/0008-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From 3f6a1691ef17be41dcf06a10d9f61f8f782c89eb Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index 14ae0cfc325e..6197c5252d2a 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.46.1 + +From 2e305391186160d0098b014174322fc7bf80f778 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.46.1 + diff --git a/patches/6.11/0009-surface-button.patch b/patches/6.11/0009-surface-button.patch new file mode 100644 index 0000000000..4630c77d60 --- /dev/null +++ b/patches/6.11/0009-surface-button.patch @@ -0,0 +1,149 @@ +From 0200cc75ca3e977b952b064efa6a1f1eb013b782 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index 5c5d407fe965..4e1bfe90e730 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.46.1 + +From 193f349dc523cfb1d718c3f3f7f1a3e1152bb726 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.46.1 + diff --git a/patches/6.11/0010-surface-typecover.patch b/patches/6.11/0010-surface-typecover.patch new file mode 100644 index 0000000000..6290fddb5a --- /dev/null +++ b/patches/6.11/0010-surface-typecover.patch @@ -0,0 +1,573 @@ +From 5685742814d25f3e7bf875d953edb3606cadf964 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 13171454f959..a83beefd25f3 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.46.1 + +From 996f946c80d5a28b533d2cb173faadf0421c05ae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 99812c0f830b..0b3b51e37149 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -34,7 +34,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -168,6 +175,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + + #define MT_DEFAULT_MAXCONTACT 10 + #define MT_MAX_MAXCONTACT 250 +@@ -396,6 +406,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_SEPARATE_APP_REPORT, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1744,6 +1764,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1767,6 +1850,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1805,15 +1891,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1863,6 +1953,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2267,6 +2358,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.46.1 + +From 299f2254f1ea935f2f59c9150556dc6e26aa6ddb Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 0b3b51e37149..481b97dce830 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -408,6 +411,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1389,6 +1393,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1416,6 +1423,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1437,6 +1459,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1444,6 +1467,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1453,11 +1489,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1634,6 +1680,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1682,6 +1764,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1764,30 +1853,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1796,8 +1861,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1931,13 +1997,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1946,12 +2023,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.46.1 + diff --git a/patches/6.11/0011-surface-shutdown.patch b/patches/6.11/0011-surface-shutdown.patch new file mode 100644 index 0000000000..1a1a30f6ac --- /dev/null +++ b/patches/6.11/0011-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 90fe04d6368553e9f920dc9ab000460d0b592cfa Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index f412ef73a6e4..9892cd72dd2c 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index a2ce4e08edf5..18b80d14bdfb 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6277,3 +6277,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 4cf89a4b4cbc..bb633c76d3a5 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -466,6 +466,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.46.1 + diff --git a/patches/6.11/0012-surface-gpe.patch b/patches/6.11/0012-surface-gpe.patch new file mode 100644 index 0000000000..416b2b711a --- /dev/null +++ b/patches/6.11/0012-surface-gpe.patch @@ -0,0 +1,51 @@ +From 27ed0b03b6cfdbc60743f77b546fe4f157a1d512 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index 62fd4004db31..103fc4468262 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.46.1 + diff --git a/patches/6.11/0013-cameras.patch b/patches/6.11/0013-cameras.patch new file mode 100644 index 0000000000..1d4b2dad69 --- /dev/null +++ b/patches/6.11/0013-cameras.patch @@ -0,0 +1,781 @@ +From 60b2e713e86789d7d6f7f28a46f8fa32c181a56a Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 22ae7829a915..0fe281280316 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2185,6 +2185,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.46.1 + +From a06834b1abe43c0afbb5f4a1e1a1e85f249cab18 Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 5df658b9811b..7e3c58c872a7 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -45,6 +45,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -223,12 +230,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -2164,6 +2173,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2466,6 +2478,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4712,6 +4727,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4759,6 +4786,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.46.1 + +From 11ccfff2684694956fb2156f8216c1275a6bd97d Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 1e107fd49f82..e3e1696e7f0e 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.46.1 + +From 469d8067637b158a501d8fa221cf7f922c021345 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 07b302e09340..baad1e50ca81 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -83,12 +83,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ { } ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity ^= GPIO_ACTIVE_LOW; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) +-- +2.46.1 + +From 7a741f318b87a42d351d142512d55f0407a7e9e3 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.46.1 + +From 8baca29ff57339999c716555b4f1d961abbec3b2 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index f19c8adf2c61..923ed1b5ab8b 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.46.1 + +From fbcac39c13e09ce4cc8ad3d4520fd03863eb52f0 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index e3e1696e7f0e..423dc555093f 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.46.1 + +From 8bbe05d964175fdebb1cd0693aade238df967362 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.46.1 + +From 8776136058fe2e8b5b1edaab6693448b37fa219d Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 8d9d8da376e4..d8597897aa83 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -933,6 +933,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 18afbb5a23ee..a1d16c0af82d 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.46.1 + +From 6e4b702fd02830ba9de5ac4fbb2eae53b02aeedc Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Sat, 3 Feb 2024 12:59:53 +0900 +Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on + stream stop + +Adapt to 009905e "media: v4l2-subdev: Document and enforce .s_stream() requirements" + +Patchset: cameras +--- + drivers/staging/media/ipu3/ipu3-v4l2.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c +index 3df58eb3e882..81aff2d5d898 100644 +--- a/drivers/staging/media/ipu3/ipu3-v4l2.c ++++ b/drivers/staging/media/ipu3/ipu3-v4l2.c +@@ -538,18 +538,18 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq) + + WARN_ON(!node->enabled); + +- pipe = node->pipe; +- dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); +- imgu_pipe = &imgu->imgu_pipe[pipe]; +- r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); +- if (r) +- dev_err(&imgu->pci_dev->dev, +- "failed to stop subdev streaming\n"); +- + mutex_lock(&imgu->streaming_lock); + /* Was this the first node with streaming disabled? */ + if (imgu->streaming && imgu_all_nodes_streaming(imgu, node)) { + /* Yes, really stop streaming now */ ++ pipe = node->pipe; ++ dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); ++ imgu_pipe = &imgu->imgu_pipe[pipe]; ++ r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); ++ if (r) ++ dev_err(&imgu->pci_dev->dev, ++ "failed to stop subdev streaming\n"); ++ + dev_dbg(dev, "IMGU streaming is ready to stop"); + r = imgu_s_stream(imgu, false); + if (!r) +-- +2.46.1 + +From 3a0e7fc61359fbfd0fef1b35579fa8f5039bb8a3 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.46.1 + diff --git a/patches/6.11/0014-amd-gpio.patch b/patches/6.11/0014-amd-gpio.patch new file mode 100644 index 0000000000..4b4029bf6c --- /dev/null +++ b/patches/6.11/0014-amd-gpio.patch @@ -0,0 +1,109 @@ +From 9d8082e995819cd474ea46b99e44f5e52f63818a Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 9f4618dcd704..639fa57b6398 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.46.1 + +From fc1eda8b7c4c5a183ba34d88a5778e68e49c59e5 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 639fa57b6398..2449b256e19b 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.46.1 + diff --git a/patches/6.11/0015-rtc.patch b/patches/6.11/0015-rtc.patch new file mode 100644 index 0000000000..92e5703f3f --- /dev/null +++ b/patches/6.11/0015-rtc.patch @@ -0,0 +1,110 @@ +From a45bcc81c1b1a9922d759de30798e9f3bd89f1ac Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index b831cb8e53dc..78bd0f926505 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.46.1 + From f9e5074cb2d16c2300a1de44628da03faa0f4525 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 20 Sep 2024 22:18:58 +0200 Subject: [PATCH 061/236] README: Update list of supported devices --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 929c9d4c6c..ecdedb00a9 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,12 @@ If your device is not listed as supported yet, feel free to open an issue. * Surface Laptop 3 * Surface Laptop 4 * Surface Laptop 5 +* Surface Laptop 6 * Surface Laptop Go * Surface Laptop Go 2 +* Surface Laptop Go 3 * Surface Laptop Studio +* Surface Laptop Studio 2 * Surface Pro 1 * Surface Pro 3 * Surface Pro 4 @@ -60,6 +63,7 @@ If your device is not listed as supported yet, feel free to open an issue. * Surface Pro 7+ * Surface Pro 8 * Surface Pro 9 +* Surface Pro 10 * Surface Studio ### Features / What's Working From a65be3d1c359d10d5ea8cd4991ef92200a35815f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Oct 2024 16:37:17 +0200 Subject: [PATCH 062/236] Update v6.10 patches Changes: - Rebase onto v6.11.4 Links: - kernel: https://github.com/linux-surface/kernel/commit/a45bcc81c1b1a9922d759de30798e9f3bd89f1ac --- patches/6.11/0001-secureboot.patch | 10 ++--- patches/6.11/0002-surface3-oemb.patch | 4 +- patches/6.11/0003-mwifiex.patch | 16 +++---- patches/6.11/0004-ath10k.patch | 4 +- patches/6.11/0005-ipts.patch | 14 +++--- patches/6.11/0006-ithc.patch | 8 ++-- patches/6.11/0007-surface-sam.patch | 12 ++--- patches/6.11/0008-surface-sam-over-hid.patch | 8 ++-- patches/6.11/0009-surface-button.patch | 8 ++-- patches/6.11/0010-surface-typecover.patch | 38 ++++++++-------- patches/6.11/0011-surface-shutdown.patch | 10 ++--- patches/6.11/0012-surface-gpe.patch | 4 +- patches/6.11/0013-cameras.patch | 46 ++++++++++---------- patches/6.11/0014-amd-gpio.patch | 12 ++--- patches/6.11/0015-rtc.patch | 4 +- 15 files changed, 99 insertions(+), 99 deletions(-) diff --git a/patches/6.11/0001-secureboot.patch b/patches/6.11/0001-secureboot.patch index 68c0b18200..840e09b5f0 100644 --- a/patches/6.11/0001-secureboot.patch +++ b/patches/6.11/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 3072491a57e495f0c1cea7d177f23b7e1b2dce4f Mon Sep 17 00:00:00 2001 +From c65813200c754d8eea4f90853ff530913f4e7756 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.46.1 +2.47.0 -From 5c2e6c9e2424f940b98ac772b9e8c6bae07563c9 Mon Sep 17 00:00:00 2001 +From 3b4f12925b7a0febe9063369302cd2ffcf9162aa Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 09126bb8cc9f..d4203d40146e 100644 +index be010fec7654..cc6e7ae5786e 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3020,6 +3020,11 @@ @@ -108,5 +108,5 @@ index 0a213f69a9e4..8e4f9dcc9f4c 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0002-surface3-oemb.patch b/patches/6.11/0002-surface3-oemb.patch index 2e36bc27da..5c48c61814 100644 --- a/patches/6.11/0002-surface3-oemb.patch +++ b/patches/6.11/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 5e2a56c28a75458faee96311074a886d18df278e Mon Sep 17 00:00:00 2001 +From d8e561d29cf04f0bc3cc956a5c20193f1e8efafe Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,5 +97,5 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0003-mwifiex.patch b/patches/6.11/0003-mwifiex.patch index ba5d9e6d4a..3758fcb79f 100644 --- a/patches/6.11/0003-mwifiex.patch +++ b/patches/6.11/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From d3dce7daa7c9b02fffc26ab4b001dd28bacc0354 Mon Sep 17 00:00:00 2001 +From ce9b11dd660f9e7509570f821bd4fa527ee5ce7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.46.1 +2.47.0 -From 9769338807b783cee28ff7bccbaa0e60c684be9f Mon Sep 17 00:00:00 2001 +From 2aaddb1037531ed3501dacbe10fbeccbfd912abb Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.46.1 +2.47.0 -From f9801752d406cd308af5286c21bb27d946d3e9c7 Mon Sep 17 00:00:00 2001 +From 842d18f931d475c631983088f0dc68590b5d01f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 51d9d4532dda..e62c565ebc6d 100644 +index a1e9b052bc84..ca5193dd1760 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 51d9d4532dda..e62c565ebc6d 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3856,6 +3858,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3861,6 +3863,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 51d9d4532dda..e62c565ebc6d 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0004-ath10k.patch b/patches/6.11/0004-ath10k.patch index 77ff702850..9638e4e61a 100644 --- a/patches/6.11/0004-ath10k.patch +++ b/patches/6.11/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 137690d1fd93f0c5f723f1734e2b8db6709f806e Mon Sep 17 00:00:00 2001 +From bf796a6f659919fc07005a3f592af73bbccec01d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index b3294287bce1..2936fdae823c 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0005-ipts.patch b/patches/6.11/0005-ipts.patch index 62533e4f68..64096dc1d0 100644 --- a/patches/6.11/0005-ipts.patch +++ b/patches/6.11/0005-ipts.patch @@ -1,4 +1,4 @@ -From 349269d5e90409c3dd12e022da4771c6a66752b6 Mon Sep 17 00:00:00 2001 +From 7b55614047170b243dc1c960a58379c8189bc542 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -35,9 +35,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.46.1 +2.47.0 -From 9c052968302b202812f519f38839dd00d3621795 Mon Sep 17 00:00:00 2001 +From 5232bb39f72e91e8ff1be56bc22967c7be5d5c26 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 4aa070cf56e7..5df658b9811b 100644 +index e3e513cabc86..d786fbda6eb3 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -40,6 +40,11 @@ @@ -142,9 +142,9 @@ index 4aa070cf56e7..5df658b9811b 100644 { if (risky_device(dev)) -- -2.46.1 +2.47.0 -From 4d098196ff771e07ce301632377779c94dfa7cb4 Mon Sep 17 00:00:00 2001 +From fc25e7b589070e501a5d34a5bbfbc1e54726bb0d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3237,5 +3237,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0006-ithc.patch b/patches/6.11/0006-ithc.patch index 6a05435705..cd5a3eafec 100644 --- a/patches/6.11/0006-ithc.patch +++ b/patches/6.11/0006-ithc.patch @@ -1,4 +1,4 @@ -From 153d9fcfbe1cd5765470d42ae7aa82825dc9ffc3 Mon Sep 17 00:00:00 2001 +From 31980f3e712c9d376ed1fbe285fddeebf2f86632 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index e090ca07364b..e575193615bf 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.46.1 +2.47.0 -From e3fd5a2f58e174fab58d777ad43a2fb378e58ce9 Mon Sep 17 00:00:00 2001 +From 80bbbf9215e6fcd4ab2614b11229b4c2f172effc Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -2767,5 +2767,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0007-surface-sam.patch b/patches/6.11/0007-surface-sam.patch index def4813d76..c9d536472e 100644 --- a/patches/6.11/0007-surface-sam.patch +++ b/patches/6.11/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 046b4dd2291ee2e379f529037eab24d6b0cee56e Mon Sep 17 00:00:00 2001 +From bf2d9c3afe03fb23296bb163ab83b49534572778 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -20,10 +20,10 @@ Patchset: surface-sam create mode 100644 drivers/hwmon/surface_temp.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index b60fe2e58ad6..70c6385f0ed6 100644 +index 778e584c3a75..b8d65292db83 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig -@@ -2080,6 +2080,16 @@ config SENSORS_SURFACE_FAN +@@ -2084,6 +2084,16 @@ config SENSORS_SURFACE_FAN Select M or Y here, if you want to be able to read the fan's speed. @@ -224,9 +224,9 @@ index 000000000000..48c3e826713f +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.46.1 +2.47.0 -From e8afedc65f5b36c2e2845e7b5848750785512817 Mon Sep 17 00:00:00 2001 +From 826d753cfebd01a24a6c8b0b454ab743628511b4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -419,5 +419,5 @@ index 48c3e826713f..4c08926139db 100644 "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, NULL); -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0008-surface-sam-over-hid.patch b/patches/6.11/0008-surface-sam-over-hid.patch index c4ede3bf82..db844cb0e9 100644 --- a/patches/6.11/0008-surface-sam-over-hid.patch +++ b/patches/6.11/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 3f6a1691ef17be41dcf06a10d9f61f8f782c89eb Mon Sep 17 00:00:00 2001 +From aac218684ff18afe0bc296766b4abdaf38c384a5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index 14ae0cfc325e..6197c5252d2a 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.46.1 +2.47.0 -From 2e305391186160d0098b014174322fc7bf80f778 Mon Sep 17 00:00:00 2001 +From ebcf9444565e3f3050e92cb6b32a8c590bd69189 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0009-surface-button.patch b/patches/6.11/0009-surface-button.patch index 4630c77d60..ff006a5b2d 100644 --- a/patches/6.11/0009-surface-button.patch +++ b/patches/6.11/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 0200cc75ca3e977b952b064efa6a1f1eb013b782 Mon Sep 17 00:00:00 2001 +From 24edbaa278fb632bc77683074b6c7b402f3fe0f2 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index 5c5d407fe965..4e1bfe90e730 100644 /* -- -2.46.1 +2.47.0 -From 193f349dc523cfb1d718c3f3f7f1a3e1152bb726 Mon Sep 17 00:00:00 2001 +From fb78e4db42f1a3c1ed6d8434ab0869f740eeebd9 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0010-surface-typecover.patch b/patches/6.11/0010-surface-typecover.patch index 6290fddb5a..2397b72c5e 100644 --- a/patches/6.11/0010-surface-typecover.patch +++ b/patches/6.11/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 5685742814d25f3e7bf875d953edb3606cadf964 Mon Sep 17 00:00:00 2001 +From a5a6bdb95712bac5c7654818ac8d4f057ef4d5cb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -37,9 +37,9 @@ index 13171454f959..a83beefd25f3 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.46.1 +2.47.0 -From 996f946c80d5a28b533d2cb173faadf0421c05ae Mon Sep 17 00:00:00 2001 +From 4ce6ba56469f18617a4498efc9a820eee619adf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 99812c0f830b..0b3b51e37149 100644 +index 847462650549..eea3fdbe28e9 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -147,7 +147,7 @@ index 99812c0f830b..0b3b51e37149 100644 { } }; -@@ -1744,6 +1764,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1745,6 +1765,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index 99812c0f830b..0b3b51e37149 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1767,6 +1850,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1768,6 +1851,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index 99812c0f830b..0b3b51e37149 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1805,15 +1891,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1806,15 +1892,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -249,7 +249,7 @@ index 99812c0f830b..0b3b51e37149 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1863,6 +1953,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1864,6 +1954,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -257,7 +257,7 @@ index 99812c0f830b..0b3b51e37149 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2267,6 +2358,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2277,6 +2368,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -270,9 +270,9 @@ index 99812c0f830b..0b3b51e37149 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.46.1 +2.47.0 -From 299f2254f1ea935f2f59c9150556dc6e26aa6ddb Mon Sep 17 00:00:00 2001 +From cf0c06dd2575c17fbe7a82e6cc40ffaeea997903 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -301,7 +301,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 0b3b51e37149..481b97dce830 100644 +index eea3fdbe28e9..382dd01beb82 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -411,7 +411,7 @@ index 0b3b51e37149..481b97dce830 100644 return 0; } -@@ -1634,6 +1680,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1635,6 +1681,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -454,7 +454,7 @@ index 0b3b51e37149..481b97dce830 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1682,6 +1764,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1683,6 +1765,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -468,7 +468,7 @@ index 0b3b51e37149..481b97dce830 100644 default: suffix = "UNKNOWN"; break; -@@ -1764,30 +1853,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1765,30 +1854,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -499,7 +499,7 @@ index 0b3b51e37149..481b97dce830 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1796,8 +1861,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1797,8 +1862,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -511,7 +511,7 @@ index 0b3b51e37149..481b97dce830 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -1931,13 +1997,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -1932,13 +1998,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -536,7 +536,7 @@ index 0b3b51e37149..481b97dce830 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1946,12 +2023,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -1947,12 +2024,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); @@ -569,5 +569,5 @@ index 0b3b51e37149..481b97dce830 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0011-surface-shutdown.patch b/patches/6.11/0011-surface-shutdown.patch index 1a1a30f6ac..8acbabf2dc 100644 --- a/patches/6.11/0011-surface-shutdown.patch +++ b/patches/6.11/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 90fe04d6368553e9f920dc9ab000460d0b592cfa Mon Sep 17 00:00:00 2001 +From f2446b2596fb644a8918c873ee6482a4632a9ed7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -37,10 +37,10 @@ index f412ef73a6e4..9892cd72dd2c 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index a2ce4e08edf5..18b80d14bdfb 100644 +index dccb60c1d9cc..7baec2d30547 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6277,3 +6277,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6298,3 +6298,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -81,7 +81,7 @@ index a2ce4e08edf5..18b80d14bdfb 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 4cf89a4b4cbc..bb633c76d3a5 100644 +index 37d97bef060f..056fce19477b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -466,6 +466,7 @@ struct pci_dev { @@ -93,5 +93,5 @@ index 4cf89a4b4cbc..bb633c76d3a5 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0012-surface-gpe.patch b/patches/6.11/0012-surface-gpe.patch index 416b2b711a..b9f661c9e8 100644 --- a/patches/6.11/0012-surface-gpe.patch +++ b/patches/6.11/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 27ed0b03b6cfdbc60743f77b546fe4f157a1d512 Mon Sep 17 00:00:00 2001 +From 9414be4b9e54845ed9f115cda63deb7687b04b38 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0013-cameras.patch b/patches/6.11/0013-cameras.patch index 1d4b2dad69..5533f69c74 100644 --- a/patches/6.11/0013-cameras.patch +++ b/patches/6.11/0013-cameras.patch @@ -1,4 +1,4 @@ -From 60b2e713e86789d7d6f7f28a46f8fa32c181a56a Mon Sep 17 00:00:00 2001 +From 1344a64b467f5d2384e8f9461b31da2ed12160bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index 22ae7829a915..0fe281280316 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.46.1 +2.47.0 -From a06834b1abe43c0afbb5f4a1e1a1e85f249cab18 Mon Sep 17 00:00:00 2001 +From aeb30182901820e1d1be4a0c15c8256212f68a11 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 5df658b9811b..7e3c58c872a7 100644 +index d786fbda6eb3..3d035ecce4f3 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -45,6 +45,13 @@ @@ -182,9 +182,9 @@ index 5df658b9811b..7e3c58c872a7 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.46.1 +2.47.0 -From 11ccfff2684694956fb2156f8216c1275a6bd97d Mon Sep 17 00:00:00 2001 +From 6bf250b751177bbaf84ed05dd3bc250ca5cd68e7 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 1e107fd49f82..e3e1696e7f0e 100644 return 0; -- -2.46.1 +2.47.0 -From 469d8067637b158a501d8fa221cf7f922c021345 Mon Sep 17 00:00:00 2001 +From 508203342e1ad02fca50a37fe5a8618fa406f13b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -275,9 +275,9 @@ index 07b302e09340..baad1e50ca81 100644 agpio, func, polarity); if (ret) -- -2.46.1 +2.47.0 -From 7a741f318b87a42d351d142512d55f0407a7e9e3 Mon Sep 17 00:00:00 2001 +From b847f014cf9f10674bdd7fd208b5f0c86d0c55ca Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -314,9 +314,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.46.1 +2.47.0 -From 8baca29ff57339999c716555b4f1d961abbec3b2 Mon Sep 17 00:00:00 2001 +From 5db7d52e79618eb92046df0cd0c73f0154f40b92 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -365,9 +365,9 @@ index f19c8adf2c61..923ed1b5ab8b 100644 if (ret < 0) goto out_cleanup; -- -2.46.1 +2.47.0 -From fbcac39c13e09ce4cc8ad3d4520fd03863eb52f0 Mon Sep 17 00:00:00 2001 +From bb1c193ae4d1148c3fc944bae4808880350a18d8 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -406,9 +406,9 @@ index e3e1696e7f0e..423dc555093f 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.46.1 +2.47.0 -From 8bbe05d964175fdebb1cd0693aade238df967362 Mon Sep 17 00:00:00 2001 +From 97b29baa3e74dfb9bf28944228c55b4902606ffd Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -447,9 +447,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.46.1 +2.47.0 -From 8776136058fe2e8b5b1edaab6693448b37fa219d Mon Sep 17 00:00:00 2001 +From 0c2ad1ee6582ab8d423b082ab0bcf9e5a91868cd Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -698,9 +698,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.46.1 +2.47.0 -From 6e4b702fd02830ba9de5ac4fbb2eae53b02aeedc Mon Sep 17 00:00:00 2001 +From 80ee359e5cf8405e32b80c3fafbf77e5aa8ce00a Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -745,9 +745,9 @@ index 3df58eb3e882..81aff2d5d898 100644 r = imgu_s_stream(imgu, false); if (!r) -- -2.46.1 +2.47.0 -From 3a0e7fc61359fbfd0fef1b35579fa8f5039bb8a3 Mon Sep 17 00:00:00 2001 +From 116b355beaaba8bfdb843cea5fb51389571111d1 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -777,5 +777,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0014-amd-gpio.patch b/patches/6.11/0014-amd-gpio.patch index 4b4029bf6c..5b086d17f4 100644 --- a/patches/6.11/0014-amd-gpio.patch +++ b/patches/6.11/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 9d8082e995819cd474ea46b99e44f5e52f63818a Mon Sep 17 00:00:00 2001 +From 80a1c3b9fcc4d2423e528428717a17e112aaf8ca Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 9f4618dcd704..639fa57b6398 100644 +index 4efecac49863..88377bb0d137 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -63,9 +63,9 @@ index 9f4618dcd704..639fa57b6398 100644 mp_config_acpi_legacy_irqs(); -- -2.46.1 +2.47.0 -From fc1eda8b7c4c5a183ba34d88a5778e68e49c59e5 Mon Sep 17 00:00:00 2001 +From f18c5286b05d2a86f48a86e401e5d04000fad114 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,7 +80,7 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 639fa57b6398..2449b256e19b 100644 +index 88377bb0d137..c58f26918b17 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) @@ -105,5 +105,5 @@ index 639fa57b6398..2449b256e19b 100644 }; -- -2.46.1 +2.47.0 diff --git a/patches/6.11/0015-rtc.patch b/patches/6.11/0015-rtc.patch index 92e5703f3f..827a8e2f3d 100644 --- a/patches/6.11/0015-rtc.patch +++ b/patches/6.11/0015-rtc.patch @@ -1,4 +1,4 @@ -From a45bcc81c1b1a9922d759de30798e9f3bd89f1ac Mon Sep 17 00:00:00 2001 +From 7cbb3d2bc50c08e87fd825e7ae0433307f5152ad Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index b831cb8e53dc..78bd0f926505 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.46.1 +2.47.0 From 92294bf97401de57d96f64741e1e4c2f109ad807 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Oct 2024 16:45:44 +0200 Subject: [PATCH 063/236] Update Arch kernel to v6.11.4 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3-oemb.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- pkg/arch/kernel/0007-surface-sam.patch | 2 +- .../kernel/0008-surface-sam-over-hid.patch | 2 +- pkg/arch/kernel/0009-surface-button.patch | 2 +- pkg/arch/kernel/0010-surface-typecover.patch | 2 +- pkg/arch/kernel/0011-surface-shutdown.patch | 2 +- pkg/arch/kernel/0012-surface-gpe.patch | 2 +- pkg/arch/kernel/0013-cameras.patch | 2 +- pkg/arch/kernel/0014-amd-gpio.patch | 2 +- pkg/arch/kernel/0015-rtc.patch | 2 +- pkg/arch/kernel/PKGBUILD | 36 +++--- pkg/arch/kernel/config | 119 ++++++++++++++---- 17 files changed, 130 insertions(+), 55 deletions(-) diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 53f1acf38e..686f88ee6e 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.10/0001-secureboot.patch \ No newline at end of file +../../../patches/6.11/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3-oemb.patch b/pkg/arch/kernel/0002-surface3-oemb.patch index 2ed0bb77ab..f8442119ab 120000 --- a/pkg/arch/kernel/0002-surface3-oemb.patch +++ b/pkg/arch/kernel/0002-surface3-oemb.patch @@ -1 +1 @@ -../../../patches/6.10/0002-surface3-oemb.patch \ No newline at end of file +../../../patches/6.11/0002-surface3-oemb.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index 0e93cc78bd..47a2aa6d8a 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.10/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.11/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index 516b0a84f6..0a9abad8fd 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.10/0004-ath10k.patch \ No newline at end of file +../../../patches/6.11/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index 006d633b22..e9cc5e8f56 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.10/0005-ipts.patch \ No newline at end of file +../../../patches/6.11/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index 9f19173f77..f981cd94f2 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.10/0006-ithc.patch \ No newline at end of file +../../../patches/6.11/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch index bfb3707e2c..340b8182a3 120000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -1 +1 @@ -../../../patches/6.10/0007-surface-sam.patch \ No newline at end of file +../../../patches/6.11/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch index 6a39f547a4..c9b7dbe548 120000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -1 +1 @@ -../../../patches/6.10/0008-surface-sam-over-hid.patch \ No newline at end of file +../../../patches/6.11/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch index 00ff866efe..f0ce82afbc 120000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -1 +1 @@ -../../../patches/6.10/0009-surface-button.patch \ No newline at end of file +../../../patches/6.11/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch index b432019d84..663d576c91 120000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -1 +1 @@ -../../../patches/6.10/0010-surface-typecover.patch \ No newline at end of file +../../../patches/6.11/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch index 21677cc427..97d2f21a58 120000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -1 +1 @@ -../../../patches/6.10/0011-surface-shutdown.patch \ No newline at end of file +../../../patches/6.11/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch index 0186089384..ffc9db7603 120000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -1 +1 @@ -../../../patches/6.10/0012-surface-gpe.patch \ No newline at end of file +../../../patches/6.11/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch index 0b99c35459..38e7b8ebd1 120000 --- a/pkg/arch/kernel/0013-cameras.patch +++ b/pkg/arch/kernel/0013-cameras.patch @@ -1 +1 @@ -../../../patches/6.10/0013-cameras.patch \ No newline at end of file +../../../patches/6.11/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch index 0be91a74dd..83eb5d9f1b 120000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -1 +1 @@ -../../../patches/6.10/0014-amd-gpio.patch \ No newline at end of file +../../../patches/6.11/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch index 94917a872d..f1c8b5a1e7 120000 --- a/pkg/arch/kernel/0015-rtc.patch +++ b/pkg/arch/kernel/0015-rtc.patch @@ -1 +1 @@ -../../../patches/6.10/0015-rtc.patch \ No newline at end of file +../../../patches/6.11/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index af13b9685a..e1ef72be8e 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.10.10.arch1 +pkgver=6.11.4.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('e520738ac445054efc1931211ca12c39e6245ce8ece95808ad4e01904ed5be1a' - '09bc22332affedcdf96cfa7b4ff3dcf1d087d1bde818b9929f5ad1102bc4f775' +sha256sums=('6927373ee4edaaba5f62b0f998afc8afdce9f65b1d3c3ba4da88cbcc8f85d308' + '85d7da72a3bfb175caa71ec26393f32c3ac7457477f53be373a94192392caef6' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - 'cb26323ca2d73b6180b468235a9a8611ca164b130d6c742a910b3d708fc88ea1' - '751d8242597e81eb45af9a5e04bea3b1206444aef004cb5f0b80de6f404b5f56' - '318c785b33790a4d5a44099d2cd8f961155b671935ac3bd519ced83a7e10b22c' - '48ac4f06b78bdc5e0b9d13c4366405accc42ad14b6623f9aeb6bf31569013b12' - 'ec3c09316a28e6046d6331f51def9f99c0cbf75f06abcf4fadbea5219b6e7d7d' - 'e6c01449502930ed924d2e127aa36240a1592a55398d6bb7a3654aa1cd3e9e45' - '8875c5688d18afe8923465f20f19a9e300125886103ce9ccc537446a265c74dd' - 'd8a69f59a70046415fe58ed6c2fadf1c6bed85c44fd739a4a692e2f3ae7c9cad' - 'edbfa3efeae6ac369dbdf922e77bddc9de2056055f27779baebb3a3c2a5f5760' - 'c9d0e7ff17855bc4a4e5e1a2aab2c50934f8ac7035766557aca1753a0cedee65' - '874fd44f469f6c7d45ed3cee48aa96e8853f0bec21508884f1d8cc838c925c70' - 'cf0a867b9859d5b1dee061defa89b2041571c6d003618c38ae7824b607731011' - '1ad798a5fb8c7a75101ea216cfb2613ef7bb44b8c717c99036dad6a1fbf2942e' - 'a6fbd34975461596de6936420dc68e93935745fd90d57d921a140d147f9b8575' - '0f3a51d4ab729072803fcac47878b7d9ce641a56f8fc02f1bfc337623e165283') + '5cfe5d045942fab6dbe0de852f6beabd5dfcf8d811ce7055f58487d62fae565e' + '257e3a056eee9c4daa203aca3a96cbff6b352663117550e13b64214e6a0e288d' + '6c7f360e4e5a3c1821aef1f67fe64e7b998fefdf8a67cbe8878756e8190c1ad0' + '3abfbfdd256c8b500b6b4a44e14e8948336e1fe585b26feba20a3cfc5612d354' + 'febffd7d115851ff6974c9624be6781c1cece7ad10492e7e6b0068c3a67a28b3' + '90acb7dd407d0d189050f67a14ce885384fb66dfd72ce03a87e07964f53bf005' + '91bf57fb58aa135211475128177b492a47246f4cb100dfe66da705886bd10fce' + '675cdaaed10c0bd0582612098159eab5dea9a1b8ee872236f11ad3fb8c920588' + '80b2dc9f7a060a9c9bac596dd1444ca4b7c21492037f72b113640c3c7aacb356' + 'b4ca88151a4b79f46303c25db5f4fd7c9fceacf7466118516dfe223c9797c46b' + 'f0b5ada4756b425881aca1fa17bb8415c74fc48d5ead36e8e2980d19dcfaa5b3' + '4aaebeb14b51eb96cb569da194c688774082e6028b183029356f71d261d3c295' + '99973b6f85dede6e2b658d39b0f8aef1ed1513d4fbd1db36cb6124e2cf3790cb' + '4daa5d8a227bbe9534ae2610113ead66fffa77f46a377de5e88ecfa83928b46a' + '313841d4c3d4cb0a9bec758b40e4364fcfe0c3258ab78a723489076d25894b9a') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index 4ad0c33a56..ea28db1d73 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,8 +1,8 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.10.5-arch1 Kernel Configuration +# Linux/x86 6.11.4-arch1 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="gcc (GCC) 14.2.1 20240805" +CONFIG_CC_VERSION_TEXT="gcc (GCC) 14.2.1 20240910" CONFIG_CC_IS_GCC=y CONFIG_GCC_VERSION=140201 CONFIG_CLANG_VERSION=0 @@ -219,7 +219,7 @@ CONFIG_CGROUPS=y CONFIG_PAGE_COUNTER=y # CONFIG_CGROUP_FAVOR_DYNMODS is not set CONFIG_MEMCG=y -CONFIG_MEMCG_KMEM=y +# CONFIG_MEMCG_V1 is not set CONFIG_BLK_CGROUP=y CONFIG_CGROUP_WRITEBACK=y CONFIG_CGROUP_SCHED=y @@ -302,7 +302,6 @@ CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_SELFTEST is not set CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y -CONFIG_KALLSYMS_BASE_RELATIVE=y CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y CONFIG_HAVE_PERF_EVENTS=y CONFIG_GUEST_PERF_EVENTS=y @@ -443,6 +442,7 @@ CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y CONFIG_SCHED_MC_PRIO=y CONFIG_X86_LOCAL_APIC=y +CONFIG_ACPI_MADT_WAKEUP=y CONFIG_X86_IO_APIC=y CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y CONFIG_X86_MCE=y @@ -510,7 +510,6 @@ CONFIG_EFI=y CONFIG_EFI_STUB=y CONFIG_EFI_HANDOVER_PROTOCOL=y CONFIG_EFI_MIXED=y -# CONFIG_EFI_FAKE_MEMMAP is not set CONFIG_EFI_RUNTIME_MAP=y # CONFIG_HZ_100 is not set # CONFIG_HZ_250 is not set @@ -773,6 +772,7 @@ CONFIG_HAVE_KVM_READONLY_MEM=y CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y CONFIG_KVM_VFIO=y CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY=y CONFIG_KVM_COMPAT=y CONFIG_HAVE_KVM_IRQ_BYPASS=y CONFIG_HAVE_KVM_NO_POLL=y @@ -780,6 +780,11 @@ CONFIG_KVM_XFER_TO_GUEST_WORK=y CONFIG_HAVE_KVM_PM_NOTIFIER=y CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y CONFIG_KVM_GENERIC_MMU_NOTIFIER=y +CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES=y +CONFIG_KVM_PRIVATE_MEM=y +CONFIG_KVM_GENERIC_PRIVATE_MEM=y +CONFIG_HAVE_KVM_ARCH_GMEM_PREPARE=y +CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE=y CONFIG_VIRTUALIZATION=y CONFIG_KVM=m CONFIG_KVM_INTEL=m @@ -961,8 +966,7 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y # end of GCOV-based kernel profiling CONFIG_HAVE_GCC_PLUGINS=y -CONFIG_GCC_PLUGINS=y -# CONFIG_GCC_PLUGIN_LATENT_ENTROPY is not set +# CONFIG_GCC_PLUGINS is not set CONFIG_FUNCTION_ALIGNMENT_4B=y CONFIG_FUNCTION_ALIGNMENT_16B=y CONFIG_FUNCTION_ALIGNMENT=16 @@ -1010,7 +1014,6 @@ CONFIG_BLK_DEV_BSG_COMMON=y CONFIG_BLK_ICQ=y CONFIG_BLK_DEV_BSGLIB=y CONFIG_BLK_DEV_INTEGRITY=y -CONFIG_BLK_DEV_INTEGRITY_T10=y CONFIG_BLK_DEV_WRITE_MOUNTED=y CONFIG_BLK_DEV_ZONED=y CONFIG_BLK_DEV_THROTTLING=y @@ -1112,11 +1115,12 @@ CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y CONFIG_ZSWAP_COMPRESSOR_DEFAULT="zstd" # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD is not set -# CONFIG_ZSWAP_ZPOOL_DEFAULT_Z3FOLD is not set +# CONFIG_ZSWAP_ZPOOL_DEFAULT_Z3FOLD_DEPRECATED is not set CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC=y CONFIG_ZSWAP_ZPOOL_DEFAULT="zsmalloc" CONFIG_ZBUD=y -CONFIG_Z3FOLD=y +# CONFIG_Z3FOLD_DEPRECATED is not set +CONFIG_HAVE_ZSMALLOC=y CONFIG_ZSMALLOC=y CONFIG_ZSMALLOC_STAT=y CONFIG_ZSMALLOC_CHAIN_SIZE=8 @@ -1128,6 +1132,7 @@ CONFIG_SLUB=y CONFIG_SLAB_MERGE_DEFAULT=y CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_SLAB_BUCKETS=y # CONFIG_SLUB_STATS is not set CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_RANDOM_KMALLOC_CACHES is not set @@ -1802,6 +1807,7 @@ CONFIG_NET_DSA_TAG_RZN1_A5PSW=m CONFIG_NET_DSA_TAG_LAN9303=m CONFIG_NET_DSA_TAG_SJA1105=m CONFIG_NET_DSA_TAG_TRAILER=m +CONFIG_NET_DSA_TAG_VSC73XX_8021Q=m CONFIG_NET_DSA_TAG_XRS700X=m CONFIG_VLAN_8021Q=m CONFIG_VLAN_8021Q_GVRP=y @@ -2275,6 +2281,11 @@ CONFIG_PCIE_DW_PLAT_HOST=y # Mobiveil-based PCIe controllers # # end of Mobiveil-based PCIe controllers + +# +# PLDA-based PCIe controllers +# +# end of PLDA-based PCIe controllers # end of PCI controller drivers # @@ -2672,6 +2683,7 @@ CONFIG_NVME_TCP=m CONFIG_NVME_TCP_TLS=y CONFIG_NVME_HOST_AUTH=y CONFIG_NVME_TARGET=m +CONFIG_NVME_TARGET_DEBUGFS=y CONFIG_NVME_TARGET_PASSTHRU=y CONFIG_NVME_TARGET_LOOP=m CONFIG_NVME_TARGET_RDMA=m @@ -2767,6 +2779,7 @@ CONFIG_PVPANIC=y CONFIG_PVPANIC_MMIO=m CONFIG_PVPANIC_PCI=m CONFIG_GP_PCI1XXXX=m +CONFIG_KEBA_CP500=m # end of Misc devices # @@ -3082,6 +3095,7 @@ CONFIG_DM_FLAKEY=m CONFIG_DM_VERITY=m CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING=y +CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING=y CONFIG_DM_VERITY_FEC=y CONFIG_DM_SWITCH=m CONFIG_DM_LOG_WRITES=m @@ -3394,6 +3408,7 @@ CONFIG_FM10K=m CONFIG_IGC=m CONFIG_IGC_LEDS=y CONFIG_IDPF=m +# CONFIG_IDPF_SINGLEQ is not set CONFIG_JME=m CONFIG_NET_VENDOR_ADI=y CONFIG_ADIN1110=m @@ -3444,6 +3459,8 @@ CONFIG_MLXSW_SPECTRUM=m CONFIG_MLXSW_SPECTRUM_DCB=y CONFIG_MLXSW_MINIMAL=m CONFIG_MLXFW=m +CONFIG_NET_VENDOR_META=y +CONFIG_FBNIC=m CONFIG_NET_VENDOR_MICREL=y CONFIG_KS8842=m CONFIG_KS8851=m @@ -3568,6 +3585,7 @@ CONFIG_DWC_XLGMAC=m CONFIG_DWC_XLGMAC_PCI=m CONFIG_NET_VENDOR_TEHUTI=y CONFIG_TEHUTI=m +CONFIG_TEHUTI_TN40=m CONFIG_NET_VENDOR_TI=y # CONFIG_TI_CPSW_PHY_SEL is not set CONFIG_TLAN=m @@ -3888,6 +3906,7 @@ CONFIG_ATH10K_SDIO=m CONFIG_ATH10K_USB=m CONFIG_ATH10K_DEBUG=y CONFIG_ATH10K_DEBUGFS=y +CONFIG_ATH10K_LEDS=y CONFIG_ATH10K_SPECTRAL=y CONFIG_ATH10K_TRACING=y CONFIG_WCN36XX=m @@ -4088,6 +4107,7 @@ CONFIG_RTL8188EE=m CONFIG_RTL8192EE=m CONFIG_RTL8821AE=m CONFIG_RTL8192CU=m +CONFIG_RTL8192DU=m CONFIG_RTLWIFI=m CONFIG_RTLWIFI_PCI=m CONFIG_RTLWIFI_USB=m @@ -4129,6 +4149,7 @@ CONFIG_RTW89_CORE=m CONFIG_RTW89_PCI=m CONFIG_RTW89_8851B=m CONFIG_RTW89_8852A=m +CONFIG_RTW89_8852B_COMMON=m CONFIG_RTW89_8852B=m CONFIG_RTW89_8852C=m CONFIG_RTW89_8922A=m @@ -4479,6 +4500,7 @@ CONFIG_INPUT_AD714X_SPI=m CONFIG_INPUT_ARIZONA_HAPTICS=m CONFIG_INPUT_ATC260X_ONKEY=m CONFIG_INPUT_BMA150=m +# CONFIG_INPUT_CS40L50_VIBRA is not set CONFIG_INPUT_E3X0_BUTTON=m CONFIG_INPUT_PCSPKR=m CONFIG_INPUT_MAX77693_HAPTIC=m @@ -4851,6 +4873,7 @@ CONFIG_SPI_AXI_SPI_ENGINE=m CONFIG_SPI_BITBANG=m CONFIG_SPI_BUTTERFLY=m CONFIG_SPI_CADENCE=m +CONFIG_SPI_CH341=m CONFIG_SPI_CS42L43=m CONFIG_SPI_DESIGNWARE=m CONFIG_SPI_DW_DMA=y @@ -5103,6 +5126,12 @@ CONFIG_GPIO_VIRTIO=m CONFIG_GPIO_SIM=m # end of Virtual GPIO drivers +# +# GPIO Debugging utilities +# +# CONFIG_GPIO_VIRTUSER is not set +# end of GPIO Debugging utilities + CONFIG_W1=m CONFIG_W1_CON=y @@ -5147,6 +5176,8 @@ CONFIG_POWER_RESET_ATC260X=m CONFIG_POWER_RESET_MT6323=y CONFIG_POWER_RESET_RESTART=y CONFIG_POWER_RESET_TPS65086=y +CONFIG_POWER_SEQUENCING=m +CONFIG_POWER_SEQUENCING_QCOM_WCN=m CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set CONFIG_POWER_SUPPLY_HWMON=y @@ -5183,6 +5214,7 @@ CONFIG_AXP288_CHARGER=m CONFIG_AXP288_FUEL_GAUGE=m CONFIG_BATTERY_MAX17040=m CONFIG_BATTERY_MAX17042=m +CONFIG_BATTERY_MAX1720X=m CONFIG_BATTERY_MAX1721X=m CONFIG_BATTERY_TWL4030_MADC=m CONFIG_CHARGER_88PM860X=m @@ -5224,6 +5256,7 @@ CONFIG_CHARGER_RT9467=m CONFIG_CHARGER_RT9471=m CONFIG_CHARGER_CROS_USBPD=m CONFIG_CHARGER_CROS_PCHG=m +CONFIG_CHARGER_CROS_CONTROL=m CONFIG_CHARGER_BD99954=m CONFIG_CHARGER_WILCO=m CONFIG_BATTERY_SURFACE=m @@ -5271,6 +5304,7 @@ CONFIG_SENSORS_ATXP1=m CONFIG_SENSORS_CHIPCAP2=m CONFIG_SENSORS_CORSAIR_CPRO=m CONFIG_SENSORS_CORSAIR_PSU=m +CONFIG_SENSORS_CROS_EC=m CONFIG_SENSORS_DRIVETEMP=m CONFIG_SENSORS_DS620=m CONFIG_SENSORS_DS1621=m @@ -5410,10 +5444,14 @@ CONFIG_SENSORS_MAX34440=m CONFIG_SENSORS_MAX8688=m CONFIG_SENSORS_MP2856=m CONFIG_SENSORS_MP2888=m +CONFIG_SENSORS_MP2891=m CONFIG_SENSORS_MP2975=m +CONFIG_SENSORS_MP2993=m CONFIG_SENSORS_MP2975_REGULATOR=y CONFIG_SENSORS_MP5023=m +CONFIG_SENSORS_MP5920=m CONFIG_SENSORS_MP5990=m +CONFIG_SENSORS_MP9941=m CONFIG_SENSORS_MPQ7932_REGULATOR=y CONFIG_SENSORS_MPQ7932=m CONFIG_SENSORS_MPQ8785=m @@ -5468,6 +5506,8 @@ CONFIG_SENSORS_INA209=m CONFIG_SENSORS_INA2XX=m CONFIG_SENSORS_INA238=m CONFIG_SENSORS_INA3221=m +CONFIG_SENSORS_SPD5118=m +CONFIG_SENSORS_SPD5118_DETECT=y CONFIG_SENSORS_TC74=m CONFIG_SENSORS_THMC50=m CONFIG_SENSORS_TMP102=m @@ -5801,6 +5841,9 @@ CONFIG_MFD_WM8994=m CONFIG_MFD_WCD934X=m CONFIG_MFD_ATC260X=m CONFIG_MFD_ATC260X_I2C=m +CONFIG_MFD_CS40L50_CORE=m +CONFIG_MFD_CS40L50_I2C=m +CONFIG_MFD_CS40L50_SPI=m CONFIG_RAVE_SP_CORE=m CONFIG_MFD_INTEL_M10_BMC_CORE=m CONFIG_MFD_INTEL_M10_BMC_SPI=m @@ -6354,6 +6397,10 @@ CONFIG_VIDEO_CAFE_CCIC=m # Qualcomm media platform drivers # +# +# Raspberry Pi media platform drivers +# + # # Renesas media platform drivers # @@ -6454,6 +6501,8 @@ CONFIG_VIDEO_CCS_PLL=m CONFIG_VIDEO_ALVIUM_CSI2=m CONFIG_VIDEO_AR0521=m CONFIG_VIDEO_GC0308=m +CONFIG_VIDEO_GC05A2=m +CONFIG_VIDEO_GC08A3=m CONFIG_VIDEO_GC2145=m CONFIG_VIDEO_HI556=m CONFIG_VIDEO_HI846=m @@ -6463,6 +6512,7 @@ CONFIG_VIDEO_IMX214=m CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX258=m CONFIG_VIDEO_IMX274=m +CONFIG_VIDEO_IMX283=m CONFIG_VIDEO_IMX290=m CONFIG_VIDEO_IMX296=m CONFIG_VIDEO_IMX319=m @@ -6859,6 +6909,7 @@ CONFIG_DRM_AMDGPU=m CONFIG_DRM_AMDGPU_SI=y CONFIG_DRM_AMDGPU_CIK=y CONFIG_DRM_AMDGPU_USERPTR=y +CONFIG_DRM_AMD_ISP=y # # ACP (Audio CoProcessor) Configuration @@ -7081,6 +7132,7 @@ CONFIG_BACKLIGHT_ADP8870=m CONFIG_BACKLIGHT_88PM860X=m CONFIG_BACKLIGHT_PCF50633=m CONFIG_BACKLIGHT_AAT2870=m +CONFIG_BACKLIGHT_LM3509=m CONFIG_BACKLIGHT_LM3630A=m CONFIG_BACKLIGHT_LM3639=m CONFIG_BACKLIGHT_LP855X=m @@ -7291,6 +7343,7 @@ CONFIG_SND_HDA_CODEC_HDMI=m CONFIG_SND_HDA_CODEC_CIRRUS=m CONFIG_SND_HDA_CODEC_CS8409=m CONFIG_SND_HDA_CODEC_CONEXANT=m +CONFIG_SND_HDA_CODEC_SENARYTECH=m CONFIG_SND_HDA_CODEC_CA0110=m CONFIG_SND_HDA_CODEC_CA0132=m CONFIG_SND_HDA_CODEC_CA0132_DSP=y @@ -7406,6 +7459,7 @@ CONFIG_SND_DESIGNWARE_PCM=y # CONFIG_SND_SOC_FSL_ESAI is not set # CONFIG_SND_SOC_FSL_MICFIL is not set CONFIG_SND_SOC_FSL_XCVR=m +CONFIG_SND_SOC_FSL_UTILS=m # CONFIG_SND_SOC_IMX_AUDMUX is not set # end of SoC Audio for Freescale CPUs @@ -7611,6 +7665,7 @@ CONFIG_SND_SOC_AK4375=m CONFIG_SND_SOC_AK4458=m CONFIG_SND_SOC_AK4554=m CONFIG_SND_SOC_AK4613=m +CONFIG_SND_SOC_AK4619=m CONFIG_SND_SOC_AK4642=m CONFIG_SND_SOC_AK5386=m CONFIG_SND_SOC_AK5558=m @@ -7644,6 +7699,7 @@ CONFIG_SND_SOC_CS35L56_SHARED=m CONFIG_SND_SOC_CS35L56_I2C=m CONFIG_SND_SOC_CS35L56_SPI=m CONFIG_SND_SOC_CS35L56_SDW=m +CONFIG_SND_SOC_CS40L50=m CONFIG_SND_SOC_CS42L42_CORE=m CONFIG_SND_SOC_CS42L42=m CONFIG_SND_SOC_CS42L42_SDW=m @@ -7667,6 +7723,8 @@ CONFIG_SND_SOC_CS43130=m CONFIG_SND_SOC_CS4341=m CONFIG_SND_SOC_CS4349=m CONFIG_SND_SOC_CS53L30=m +CONFIG_SND_SOC_CS530X=m +CONFIG_SND_SOC_CS530X_I2C=m CONFIG_SND_SOC_CX2072X=m CONFIG_SND_SOC_DA7213=m CONFIG_SND_SOC_DA7219=m @@ -7675,6 +7733,7 @@ CONFIG_SND_SOC_HDMI_CODEC=m CONFIG_SND_SOC_ES7134=m CONFIG_SND_SOC_ES7241=m CONFIG_SND_SOC_ES83XX_DSM_COMMON=m +CONFIG_SND_SOC_ES8311=m CONFIG_SND_SOC_ES8316=m CONFIG_SND_SOC_ES8326=m CONFIG_SND_SOC_ES8328=m @@ -7737,6 +7796,7 @@ CONFIG_SND_SOC_RT1308=m CONFIG_SND_SOC_RT1308_SDW=m CONFIG_SND_SOC_RT1316_SDW=m CONFIG_SND_SOC_RT1318_SDW=m +CONFIG_SND_SOC_RT1320_SDW=m CONFIG_SND_SOC_RT5514=m CONFIG_SND_SOC_RT5514_SPI=m CONFIG_SND_SOC_RT5616=m @@ -7824,6 +7884,8 @@ CONFIG_SND_SOC_WCD_CLASSH=m CONFIG_SND_SOC_WCD9335=m CONFIG_SND_SOC_WCD_MBHC=m CONFIG_SND_SOC_WCD934X=m +CONFIG_SND_SOC_WCD937X=m +CONFIG_SND_SOC_WCD937X_SDW=m CONFIG_SND_SOC_WCD938X=m CONFIG_SND_SOC_WCD938X_SDW=m CONFIG_SND_SOC_WCD939X=m @@ -8558,7 +8620,6 @@ CONFIG_MS_BLOCK=m CONFIG_MEMSTICK_TIFM_MS=m CONFIG_MEMSTICK_JMICRON_38X=m CONFIG_MEMSTICK_R592=m -CONFIG_MEMSTICK_REALTEK_PCI=m CONFIG_MEMSTICK_REALTEK_USB=m CONFIG_LEDS_EXPRESSWIRE=y CONFIG_NEW_LEDS=y @@ -8574,6 +8635,7 @@ CONFIG_LEDS_88PM860X=m CONFIG_LEDS_APU=m CONFIG_LEDS_AW200XX=m CONFIG_LEDS_CHT_WCOVE=m +CONFIG_LEDS_CROS_EC=m CONFIG_LEDS_LM3530=m CONFIG_LEDS_LM3532=m CONFIG_LEDS_LM3533=m @@ -8618,6 +8680,7 @@ CONFIG_LEDS_MLXCPLD=m CONFIG_LEDS_MLXREG=m CONFIG_LEDS_USER=m CONFIG_LEDS_NIC78BX=m +CONFIG_LEDS_SPI_BYTE=m CONFIG_LEDS_TI_LMU_COMMON=m CONFIG_LEDS_LM36274=m CONFIG_LEDS_TPS6105X=m @@ -8634,6 +8697,7 @@ CONFIG_LEDS_SGM3140=m # # RGB LED drivers # +CONFIG_LEDS_KTD202X=m CONFIG_LEDS_PWM_MULTICOLOR=m CONFIG_LEDS_MT6370_RGB=m @@ -8661,6 +8725,7 @@ CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_NETDEV=m CONFIG_LEDS_TRIGGER_PATTERN=m CONFIG_LEDS_TRIGGER_TTY=m +CONFIG_LEDS_TRIGGER_INPUT_EVENTS=m # # Simple LED drivers @@ -9025,6 +9090,7 @@ CONFIG_VP_VDPA=m CONFIG_ALIBABA_ENI_VDPA=m CONFIG_SNET_VDPA=m CONFIG_PDS_VDPA=m +CONFIG_OCTEONEP_VDPA=m CONFIG_VHOST_IOTLB=m CONFIG_VHOST_RING=m CONFIG_VHOST_TASK=y @@ -9145,7 +9211,6 @@ CONFIG_STAGING_MEDIA=y CONFIG_DVB_AV7110_IR=y CONFIG_DVB_AV7110=m CONFIG_DVB_AV7110_OSD=y -CONFIG_DVB_BUDGET_PATCH=m CONFIG_DVB_SP8870=m CONFIG_VIDEO_IPU3_IMGU=m @@ -9191,6 +9256,7 @@ CONFIG_WILCO_EC=m CONFIG_WILCO_EC_DEBUGFS=m CONFIG_WILCO_EC_EVENTS=m CONFIG_WILCO_EC_TELEMETRY=m +CONFIG_CZNIC_PLATFORMS=y CONFIG_MELLANOX_PLATFORM=y CONFIG_MLXREG_HOTPLUG=m CONFIG_MLXREG_IO=m @@ -9247,6 +9313,7 @@ CONFIG_DCDBAS=m CONFIG_DELL_LAPTOP=m # CONFIG_DELL_RBU is not set CONFIG_DELL_RBTN=m +CONFIG_DELL_PC=m CONFIG_DELL_SMBIOS=m CONFIG_DELL_SMBIOS_WMI=y CONFIG_DELL_SMBIOS_SMM=y @@ -9324,7 +9391,9 @@ CONFIG_INTEL_PUNIT_IPC=m CONFIG_INTEL_RST=m CONFIG_INTEL_SDSI=m CONFIG_INTEL_SMARTCONNECT=m +CONFIG_INTEL_TPMI_POWER_DOMAINS=m CONFIG_INTEL_TPMI=m +CONFIG_INTEL_PLR_TPMI=m CONFIG_INTEL_TURBO_MAX_3=y CONFIG_INTEL_VSEC=m CONFIG_ACPI_QUICKSTART=m @@ -9677,6 +9746,7 @@ CONFIG_AD7280=m CONFIG_AD7291=m CONFIG_AD7292=m CONFIG_AD7298=m +CONFIG_AD7380=m CONFIG_AD7476=m CONFIG_AD7606=m CONFIG_AD7606_IFACE_PARALLEL=m @@ -9692,7 +9762,6 @@ CONFIG_AD7944=m CONFIG_AD7949=m CONFIG_AD799X=m CONFIG_AD9467=m -CONFIG_ADI_AXI_ADC=m CONFIG_AXP20X_ADC=m CONFIG_AXP288_ADC=m CONFIG_CC10001_ADC=m @@ -9723,6 +9792,7 @@ CONFIG_MCP320X=m CONFIG_MCP3422=m CONFIG_MCP3564=m CONFIG_MCP3911=m +CONFIG_MEDIATEK_MT6359_AUXADC=m CONFIG_MEDIATEK_MT6360_ADC=m CONFIG_MEDIATEK_MT6370_ADC=m CONFIG_MEN_Z188_ADC=m @@ -9740,6 +9810,7 @@ CONFIG_TI_ADC108S102=m CONFIG_TI_ADC128S052=m CONFIG_TI_ADC161S626=m CONFIG_TI_ADS1015=m +CONFIG_TI_ADS1119=m CONFIG_TI_ADS7924=m CONFIG_TI_ADS1100=m CONFIG_TI_ADS1298=m @@ -9796,6 +9867,9 @@ CONFIG_BME680=m CONFIG_BME680_I2C=m CONFIG_BME680_SPI=m CONFIG_CCS811=m +CONFIG_ENS160=m +CONFIG_ENS160_I2C=m +CONFIG_ENS160_SPI=m CONFIG_IAQCORE=m CONFIG_PMS7003=m CONFIG_SCD30_CORE=m @@ -9857,7 +9931,6 @@ CONFIG_AD5593R=m CONFIG_AD5504=m CONFIG_AD5624R_SPI=m CONFIG_AD9739A=m -CONFIG_ADI_AXI_DAC=m CONFIG_LTC2688=m CONFIG_AD5686=m CONFIG_AD5686_SPI=m @@ -10080,6 +10153,7 @@ CONFIG_US5182D=m CONFIG_VCNL4000=m CONFIG_VCNL4035=m CONFIG_VEML6030=m +CONFIG_VEML6040=m CONFIG_VEML6070=m CONFIG_VEML6075=m CONFIG_VL6180=m @@ -10276,6 +10350,7 @@ CONFIG_PWM_CRC=m CONFIG_PWM_CROS_EC=m CONFIG_PWM_DWC_CORE=m CONFIG_PWM_DWC=m +CONFIG_PWM_GPIO=m CONFIG_PWM_IQS620A=m CONFIG_PWM_LP3943=m CONFIG_PWM_LPSS=m @@ -10288,6 +10363,7 @@ CONFIG_PWM_TWL_LED=m # # IRQ chip support # +CONFIG_LAN966X_OIC=m CONFIG_MADERA_IRQ=m # end of IRQ chip support @@ -10578,9 +10654,9 @@ CONFIG_OVERLAY_FS_METACOPY=y # CONFIG_NETFS_SUPPORT=m CONFIG_NETFS_STATS=y +CONFIG_NETFS_DEBUG=y CONFIG_FSCACHE=y CONFIG_FSCACHE_STATS=y -# CONFIG_FSCACHE_DEBUG is not set CONFIG_CACHEFILES=m # CONFIG_CACHEFILES_DEBUG is not set # CONFIG_CACHEFILES_ERROR_INJECTION is not set @@ -10887,6 +10963,9 @@ CONFIG_ENCRYPTED_KEYS=m CONFIG_KEY_DH_OPERATIONS=y CONFIG_KEY_NOTIFICATIONS=y CONFIG_SECURITY_DMESG_RESTRICT=y +CONFIG_PROC_MEM_ALWAYS_FORCE=y +# CONFIG_PROC_MEM_FORCE_PTRACE is not set +# CONFIG_PROC_MEM_NO_FORCE is not set CONFIG_SECURITY=y CONFIG_SECURITYFS=y CONFIG_SECURITY_NETWORK=y @@ -10965,7 +11044,6 @@ CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y # CONFIG_INIT_STACK_NONE is not set # CONFIG_INIT_STACK_ALL_PATTERN is not set CONFIG_INIT_STACK_ALL_ZERO=y -# CONFIG_GCC_PLUGIN_STACKLEAK is not set CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y # CONFIG_INIT_ON_FREE_DEFAULT_ON is not set CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y @@ -10980,8 +11058,6 @@ CONFIG_LIST_HARDENED=y # end of Hardening of kernel data structures CONFIG_RANDSTRUCT_NONE=y -# CONFIG_RANDSTRUCT_FULL is not set -# CONFIG_RANDSTRUCT_PERFORMANCE is not set # end of Kernel hardening options # end of Security options @@ -11038,7 +11114,6 @@ CONFIG_CRYPTO_ECC=y CONFIG_CRYPTO_ECDH=y CONFIG_CRYPTO_ECDSA=y CONFIG_CRYPTO_ECRDSA=m -CONFIG_CRYPTO_SM2=m CONFIG_CRYPTO_CURVE25519=m # end of Public-key cryptography @@ -11417,13 +11492,14 @@ CONFIG_CLZ_TAB=y CONFIG_IRQ_POLL=y CONFIG_MPILIB=y CONFIG_SIGNATURE=y -CONFIG_DIMLIB=m +CONFIG_DIMLIB=y CONFIG_OID_REGISTRY=y CONFIG_UCS2_STRING=y CONFIG_HAVE_GENERIC_VDSO=y CONFIG_GENERIC_GETTIMEOFDAY=y CONFIG_GENERIC_VDSO_TIME_NS=y CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT=y +CONFIG_VDSO_GETRANDOM=y CONFIG_FONT_SUPPORT=y CONFIG_FONTS=y CONFIG_FONT_8x8=y @@ -11501,7 +11577,7 @@ CONFIG_PAHOLE_HAS_SPLIT_BTF=y CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y CONFIG_DEBUG_INFO_BTF_MODULES=y # CONFIG_MODULE_ALLOW_BTF_MISMATCH is not set -# CONFIG_GDB_SCRIPTS is not set +CONFIG_GDB_SCRIPTS=y CONFIG_FRAME_WARN=2048 CONFIG_STRIP_ASM_SYMS=y # CONFIG_READABLE_ASM is not set @@ -11839,7 +11915,6 @@ CONFIG_ASYNC_RAID6_TEST=m # CONFIG_TEST_LKM is not set # CONFIG_TEST_BITOPS is not set # CONFIG_TEST_VMALLOC is not set -# CONFIG_TEST_USER_COPY is not set # CONFIG_TEST_BPF is not set # CONFIG_TEST_BLACKHOLE_DEV is not set # CONFIG_FIND_BIT_BENCHMARK is not set From 669c5b9ed676b743d2d68cad919fdae604ed23e5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Oct 2024 16:48:01 +0200 Subject: [PATCH 064/236] Update Fedora kernels to v6.11.4 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 7dcdb8020d..2663c26fc3 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.10.10-0" +PACKAGE_TAG = "kernel-6.11.4-0" ## ## The release number of the modified kernel package. From 260b202ade51ae01f4bf5f4a5516559bd5f04973 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Oct 2024 20:12:25 +0200 Subject: [PATCH 065/236] pkg/fedora: Update Fedora-specific build patches --- .../kernel-surface/patches/0001-iptsd.patch | 8 +++---- .../patches/0002-provides.patch | 16 ++++++------- .../patches/0003-obsoletes.patch | 24 +++++++++---------- .../patches/0004-default-kernel.patch | 18 +++++++------- .../kernel-surface/patches/0005-ipu3-fw.patch | 8 +++---- .../secureboot/0001-secureboot.patch | 14 +++++------ 6 files changed, 44 insertions(+), 44 deletions(-) diff --git a/pkg/fedora/kernel-surface/patches/0001-iptsd.patch b/pkg/fedora/kernel-surface/patches/0001-iptsd.patch index 6f98383ead..3bc6dc4a72 100644 --- a/pkg/fedora/kernel-surface/patches/0001-iptsd.patch +++ b/pkg/fedora/kernel-surface/patches/0001-iptsd.patch @@ -1,4 +1,4 @@ -From 4e9c0d02238463cd3b7dbcb6b255b553191a9761 Mon Sep 17 00:00:00 2001 +From 7edf2d0d7cb87dc6c1af96d6d5cb2b0c906261d6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:33:03 +0200 Subject: [PATCH 1/5] Pull in iptsd as a weak dependency @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 21f48fb7da63..f32befeebec3 100644 +index c0201430e851..a24eae4e25e4 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1019,6 +1019,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1043,6 +1043,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index 21f48fb7da63..f32befeebec3 100644 Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -- -2.46.0 +2.47.0 diff --git a/pkg/fedora/kernel-surface/patches/0002-provides.patch b/pkg/fedora/kernel-surface/patches/0002-provides.patch index 83095ba134..3e5e86c4ca 100644 --- a/pkg/fedora/kernel-surface/patches/0002-provides.patch +++ b/pkg/fedora/kernel-surface/patches/0002-provides.patch @@ -1,4 +1,4 @@ -From 519d55a4d8be9d6278ae6d842bf0d68238e670b6 Mon Sep 17 00:00:00 2001 +From 41770a97d1ea6e590697a6c3319b2d39581eab4d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:34:38 +0200 Subject: [PATCH 2/5] Let kernel-surface provide the standard package names @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 5 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index f32befeebec3..785bc32d0544 100644 +index a24eae4e25e4..3b6c46b930e7 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -653,6 +653,7 @@ Requires: kernel-core-uname-r = %{KVERREL} +@@ -665,6 +665,7 @@ Requires: kernel-core-uname-r = %{KVERREL} Requires: kernel-modules-uname-r = %{KVERREL} Requires: kernel-modules-core-uname-r = %{KVERREL} Provides: installonlypkg(kernel) @@ -20,7 +20,7 @@ index f32befeebec3..785bc32d0544 100644 %endif -@@ -1351,6 +1352,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} +@@ -1375,6 +1376,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} Provides: kernel%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release}\ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1:+%{1}}}\ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -28,7 +28,7 @@ index f32befeebec3..785bc32d0544 100644 Provides: installonlypkg(kernel)\ AutoReqProv: no\ Requires(pre): findutils\ -@@ -1380,6 +1382,7 @@ against the %{?2:%{2} }kernel package.\ +@@ -1404,6 +1406,7 @@ against the %{?2:%{2} }kernel package.\ Summary: Meta package to install matching core and devel packages for a given %{?2:%{2} }kernel\ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ @@ -36,7 +36,7 @@ index f32befeebec3..785bc32d0544 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1501,6 +1504,7 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ +@@ -1525,6 +1528,7 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ Requires: realtime-setup\ %endif\ Provides: installonlypkg(kernel)\ @@ -44,7 +44,7 @@ index f32befeebec3..785bc32d0544 100644 %description %{1}\ The meta-package for the %{1} kernel\ %{nil} -@@ -1534,6 +1538,7 @@ This package provides KVM modules for package kernel%{?1:-%{1}}.\ +@@ -1558,6 +1562,7 @@ This package provides KVM modules for package kernel%{?1:-%{1}}.\ Summary: %{variant_summary}\ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: installonlypkg(kernel)\ @@ -53,5 +53,5 @@ index f32befeebec3..785bc32d0544 100644 Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ -- -2.46.0 +2.47.0 diff --git a/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch b/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch index 6358f53102..52f1c5d18b 100644 --- a/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch +++ b/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch @@ -1,4 +1,4 @@ -From 33807d72f32905d0e5627904be5263d7a126bf36 Mon Sep 17 00:00:00 2001 +From 4da3688eddb23be31b8560e6c437fd7fe86ad809 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:40:32 +0200 Subject: [PATCH 3/5] Let kernel-surface conflict with older versions of the @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 20 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 785bc32d0544..890d9225edd8 100644 +index 3b6c46b930e7..3b44b904b025 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -654,6 +654,10 @@ Requires: kernel-modules-uname-r = %{KVERREL} +@@ -666,6 +666,10 @@ Requires: kernel-modules-uname-r = %{KVERREL} Requires: kernel-modules-core-uname-r = %{KVERREL} Provides: installonlypkg(kernel) Provides: kernel = %{KVERREL} @@ -24,7 +24,7 @@ index 785bc32d0544..890d9225edd8 100644 %endif -@@ -1354,6 +1358,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff +@@ -1378,6 +1382,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: kernel-devel = %{KVERREL}%{?1:+%{1}}\ Provides: installonlypkg(kernel)\ @@ -33,7 +33,7 @@ index 785bc32d0544..890d9225edd8 100644 AutoReqProv: no\ Requires(pre): findutils\ Requires: findutils\ -@@ -1383,6 +1389,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ +@@ -1407,6 +1413,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ Provides: kernel-devel-matched = %{specrpmversion}-%{release}\ @@ -42,7 +42,7 @@ index 785bc32d0544..890d9225edd8 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1415,6 +1423,8 @@ Provides: kernel%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix +@@ -1439,6 +1447,8 @@ Provides: kernel%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -51,7 +51,7 @@ index 785bc32d0544..890d9225edd8 100644 AutoReq: no\ AutoProv: yes\ %description %{?1:%{1}-}modules-internal\ -@@ -1436,6 +1446,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? +@@ -1460,6 +1470,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -60,7 +60,7 @@ index 785bc32d0544..890d9225edd8 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-extra-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1459,6 +1471,8 @@ Provides: installonlypkg(kernel-module)\ +@@ -1483,6 +1495,8 @@ Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -69,7 +69,7 @@ index 785bc32d0544..890d9225edd8 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1481,6 +1495,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: +@@ -1505,6 +1519,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -78,7 +78,7 @@ index 785bc32d0544..890d9225edd8 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1503,6 +1519,8 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ +@@ -1527,6 +1543,8 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ %if "%{1}" == "rt" || "%{1}" == "rt-debug"\ Requires: realtime-setup\ %endif\ @@ -87,7 +87,7 @@ index 785bc32d0544..890d9225edd8 100644 Provides: installonlypkg(kernel)\ Provides: kernel = %{KVERREL}+%{1}\ %description %{1}\ -@@ -1539,6 +1557,8 @@ Summary: %{variant_summary}\ +@@ -1563,6 +1581,8 @@ Summary: %{variant_summary}\ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: installonlypkg(kernel)\ Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{?1:+%{1}}\ @@ -97,5 +97,5 @@ index 785bc32d0544..890d9225edd8 100644 Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ -- -2.46.0 +2.47.0 diff --git a/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch b/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch index 4a00496528..d61964488c 100644 --- a/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch +++ b/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch @@ -1,4 +1,4 @@ -From ddb9b1b93df3bf75843ab952534a39a7e8dd7711 Mon Sep 17 00:00:00 2001 +From e4184318977732138664afe43f9e1083ed530dc3 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:41:11 +0200 Subject: [PATCH 4/5] Install scripts and service files for keeping the surface @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 33 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 890d9225edd8..68b06ba0d4b1 100644 +index 3b44b904b025..d4adb18e6024 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -992,6 +992,11 @@ Source4000: README.rst +@@ -1016,6 +1016,11 @@ Source4000: README.rst Source4001: rpminspect.yaml Source4002: gating.yaml @@ -25,7 +25,7 @@ index 890d9225edd8..68b06ba0d4b1 100644 ## Patches needed for building this package %if !%{nopatches} -@@ -1025,6 +1030,7 @@ Requires(pre): %{initrd_prereq}\ +@@ -1049,6 +1054,7 @@ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ Recommends: iptsd\ @@ -33,7 +33,7 @@ index 890d9225edd8..68b06ba0d4b1 100644 Requires(preun): systemd >= 200\ Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -@@ -1039,6 +1045,13 @@ AutoProv: yes\ +@@ -1063,6 +1069,13 @@ AutoProv: yes\ %{nil} @@ -47,7 +47,7 @@ index 890d9225edd8..68b06ba0d4b1 100644 %package doc Summary: Various documentation bits found in the kernel source Group: Documentation -@@ -3170,6 +3183,11 @@ find Documentation -type d | xargs chmod u+w +@@ -3242,6 +3255,11 @@ find Documentation -type d | xargs chmod u+w cd linux-%{KVERREL} @@ -59,7 +59,7 @@ index 890d9225edd8..68b06ba0d4b1 100644 # re-define RPM_VMLINUX_H, because it doesn't carry over from %build RPM_VMLINUX_H="$(cat ../vmlinux_h_path)" -@@ -3441,6 +3459,15 @@ popd +@@ -3513,6 +3531,15 @@ popd ### scripts ### @@ -75,7 +75,7 @@ index 890d9225edd8..68b06ba0d4b1 100644 %if %{with_tools} %post -n %{package_name}-tools-libs /sbin/ldconfig -@@ -3904,6 +3931,12 @@ fi\ +@@ -3980,6 +4007,12 @@ fi\ %{_libexecdir}/kselftests %endif @@ -89,5 +89,5 @@ index 890d9225edd8..68b06ba0d4b1 100644 %if %{with_up_base} %ifnarch %nobuildarches noarch -- -2.46.0 +2.47.0 diff --git a/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch b/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch index bd2fa4d184..dc5de5d6a6 100644 --- a/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch +++ b/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch @@ -1,4 +1,4 @@ -From 47af57cd4a28cde0cecfdbb7d55197569a5af721 Mon Sep 17 00:00:00 2001 +From 051436f2db94eea7b56a3bf993915b8cc16481f4 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Mon, 29 Jan 2024 19:26:41 +0100 Subject: [PATCH 5/5] Pull in intel-vsc-firmware @@ -9,10 +9,10 @@ This package contains the IPU3 firmware needed for camera support. 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 68b06ba0d4b1..40882a465616 100644 +index d4adb18e6024..f236b4807592 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1029,6 +1029,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1053,6 +1053,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index 68b06ba0d4b1..40882a465616 100644 Recommends: %{package_name}-default-watchdog\ Requires(preun): systemd >= 200\ -- -2.46.0 +2.47.0 diff --git a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch index 4fff32a0da..8dcd54c6bb 100644 --- a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch +++ b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 4283ba47e3bfc34f6d4253b9ece50622d3815b97 Mon Sep 17 00:00:00 2001 +From 3a1ef54d409e25bd0d5f52e1c0f7f226668e79c3 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:45:33 +0200 Subject: [PATCH] Use a custom key and certificate for Secure Boot signing @@ -9,18 +9,18 @@ Signed-off-by: Dorian Stoll 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 21f48fb7da63..d411e2cd2eda 100644 +index c0201430e851..7a70246dc91b 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -759,6 +759,7 @@ BuildRequires: system-sb-certs - %ifarch x86_64 aarch64 +@@ -774,6 +774,7 @@ BuildRequires: system-sb-certs + %ifarch x86_64 aarch64 riscv64 BuildRequires: nss-tools BuildRequires: pesign >= 0.10-4 +BuildRequires: sbsigntools %endif %endif %endif -@@ -830,6 +831,13 @@ Source13: redhatsecureboot501.cer +@@ -847,6 +848,13 @@ Source13: redhatsecureboot501.cer %define signing_key_filename kernel-signing-s390.cer %endif @@ -34,7 +34,7 @@ index 21f48fb7da63..d411e2cd2eda 100644 # Fedora/ELN pesign macro expects to see these cert file names, see: # https://github.com/rhboot/pesign/blob/main/src/pesign-rpmbuild-helper.in#L216 %if 0%{?fedora}%{?eln} -@@ -2192,7 +2200,7 @@ BuildKernel() { +@@ -2235,7 +2243,7 @@ BuildKernel() { %ifarch x86_64 aarch64 %{log_msg "Sign kernel image"} @@ -44,5 +44,5 @@ index 21f48fb7da63..d411e2cd2eda 100644 %ifarch s390x ppc64le if [ -x /usr/bin/rpm-sign ]; then -- -2.46.0 +2.47.0 From 4ddda622e3550b98a3cdd2ac1eceacaaebd38956 Mon Sep 17 00:00:00 2001 From: Benjamin Otto Date: Tue, 5 Nov 2024 22:51:36 +0100 Subject: [PATCH 066/236] Remove support for Fedora 39 --- .github/workflows/fedora-39.yml | 125 -------------------------------- scripts/tag-release.sh | 2 - 2 files changed, 127 deletions(-) delete mode 100644 .github/workflows/fedora-39.yml diff --git a/.github/workflows/fedora-39.yml b/.github/workflows/fedora-39.yml deleted file mode 100644 index b029a59b76..0000000000 --- a/.github/workflows/fedora-39.yml +++ /dev/null @@ -1,125 +0,0 @@ -name: Fedora 39 - -env: - FEDORA: 39 - GPG_KEY_ID: 56C464BAAC421453 - -on: - push: - tags: - - 'fedora-39-*' - - repository_dispatch: - workflow_dispatch: - -jobs: - build: - name: Build Kernel - runs-on: ubuntu-latest - steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 5120 - remove-dotnet: true - remove-android: true - remove-docker-images: true - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Initialize containers - run: | - bash ./.github/scripts/container/create.sh \ - registry.fedoraproject.org/fedora:${{ env.FEDORA }} - - - name: Install build dependencies - run: | - bash ./.github/scripts/container/exec.sh \ - -- \ - bash ./.github/scripts/package/fedora.sh setup-builddeps - - - name: Setup secureboot certificate - env: - SB_KEY: ${{ secrets.SURFACE_SB_KEY }} - run: | - bash ./.github/scripts/container/exec.sh \ - -e SB_KEY \ - -- \ - bash ./.github/scripts/package/fedora.sh setup-secureboot - - - name: Build packages - run: | - bash ./.github/scripts/container/exec.sh \ - -- \ - bash ./.github/scripts/package/fedora.sh build-packages - - - name: Sign packages - env: - GPG_KEY: ${{ secrets.LINUX_SURFACE_GPG_KEY }} - run: | - bash ./.github/scripts/container/exec.sh \ - -e GPG_KEY \ - -e GPG_KEY_ID \ - -- \ - bash ./.github/scripts/package/fedora.sh sign-packages - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: fedora-${{ env.FEDORA }}-latest - path: pkg/fedora/kernel-surface/out/x86_64 - - release: - name: Publish release - if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/') - needs: [build] - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v3 - with: - name: fedora-${{ env.FEDORA }}-latest - path: fedora-${{ env.FEDORA }}-latest - - - name: Upload assets - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} - file: ./*-latest/* - tag: ${{ github.ref }} - overwrite: true - file_glob: true - - repo: - name: Update package repository - needs: [release] - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Download artifacts - uses: actions/download-artifact@v3 - with: - name: fedora-${{ env.FEDORA }}-latest - path: fedora-${{ env.FEDORA }}-latest - - - name: Initialize containers - run: | - bash ./.github/scripts/container/create.sh \ - registry.fedoraproject.org/fedora:${{ env.FEDORA }} - - - name: Update repository - env: - SURFACEBOT_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} - GIT_REF: ${{ github.ref }} - BRANCH_STAGING: u/staging - run: | - bash ./.github/scripts/container/exec.sh \ - -e SURFACEBOT_TOKEN \ - -e GIT_REF \ - -e BRANCH_STAGING \ - -e GITHUB_REPOSITORY \ - -- \ - bash ./.github/scripts/repository/fedora.sh ${{ env.FEDORA }} diff --git a/scripts/tag-release.sh b/scripts/tag-release.sh index 8f57f6f9c8..27629eb108 100755 --- a/scripts/tag-release.sh +++ b/scripts/tag-release.sh @@ -88,6 +88,4 @@ getfedora() tag 'arch' "$(getarch)" tag 'debian' "$(getdebian)" -tag 'fedora-38' "$(getfedora)" -tag 'fedora-39' "$(getfedora)" tag 'fedora-40' "$(getfedora)" From 654687aa3efbc32d68d912f7890e86022d095b2d Mon Sep 17 00:00:00 2001 From: Benjamin Otto Date: Tue, 5 Nov 2024 22:53:03 +0100 Subject: [PATCH 067/236] scripts: Add support for tagging Fedora 41 releases --- scripts/tag-release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/tag-release.sh b/scripts/tag-release.sh index 27629eb108..a1fb7f6473 100755 --- a/scripts/tag-release.sh +++ b/scripts/tag-release.sh @@ -89,3 +89,4 @@ getfedora() tag 'arch' "$(getarch)" tag 'debian' "$(getdebian)" tag 'fedora-40' "$(getfedora)" +tag 'fedora-41' "$(getfedora)" From ed053b1b818f569ea2860f03578098ef16c55efa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 10 Dec 2024 19:52:52 +0100 Subject: [PATCH 068/236] Update v6.11 patches Changes: - Rebase onto v6.11.11 Links: - kernel: https://github.com/linux-surface/kernel/commit/a45bcc81c1b1a9922d759de30798e9f3bd89f1ac --- patches/6.11/0001-secureboot.patch | 8 +-- patches/6.11/0002-surface3-oemb.patch | 4 +- patches/6.11/0003-mwifiex.patch | 16 +++--- patches/6.11/0004-ath10k.patch | 4 +- patches/6.11/0005-ipts.patch | 22 ++++---- patches/6.11/0006-ithc.patch | 8 +-- patches/6.11/0007-surface-sam.patch | 8 +-- patches/6.11/0008-surface-sam-over-hid.patch | 8 +-- patches/6.11/0009-surface-button.patch | 8 +-- patches/6.11/0010-surface-typecover.patch | 18 +++---- patches/6.11/0011-surface-shutdown.patch | 4 +- patches/6.11/0012-surface-gpe.patch | 4 +- patches/6.11/0013-cameras.patch | 54 ++++++++++---------- patches/6.11/0014-amd-gpio.patch | 8 +-- patches/6.11/0015-rtc.patch | 4 +- 15 files changed, 89 insertions(+), 89 deletions(-) diff --git a/patches/6.11/0001-secureboot.patch b/patches/6.11/0001-secureboot.patch index 840e09b5f0..056bf30e85 100644 --- a/patches/6.11/0001-secureboot.patch +++ b/patches/6.11/0001-secureboot.patch @@ -1,4 +1,4 @@ -From c65813200c754d8eea4f90853ff530913f4e7756 Mon Sep 17 00:00:00 2001 +From 505a0ba56061dd331e950bcd43fe2266972ccc96 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.47.0 +2.47.1 -From 3b4f12925b7a0febe9063369302cd2ffcf9162aa Mon Sep 17 00:00:00 2001 +From 0494ea66d3d0a1de801409b6e9a60b12be6a254b Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -108,5 +108,5 @@ index 0a213f69a9e4..8e4f9dcc9f4c 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0002-surface3-oemb.patch b/patches/6.11/0002-surface3-oemb.patch index 5c48c61814..98d7c06f75 100644 --- a/patches/6.11/0002-surface3-oemb.patch +++ b/patches/6.11/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From d8e561d29cf04f0bc3cc956a5c20193f1e8efafe Mon Sep 17 00:00:00 2001 +From 81226380de9cd987ca5e358eb8dd7cd26928416f Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,5 +97,5 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0003-mwifiex.patch b/patches/6.11/0003-mwifiex.patch index 3758fcb79f..022627a1d9 100644 --- a/patches/6.11/0003-mwifiex.patch +++ b/patches/6.11/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From ce9b11dd660f9e7509570f821bd4fa527ee5ce7a Mon Sep 17 00:00:00 2001 +From 38ec660bc429bf686de0ba064daf93afb7b6b7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.47.0 +2.47.1 -From 2aaddb1037531ed3501dacbe10fbeccbfd912abb Mon Sep 17 00:00:00 2001 +From 31aea914a54c2324e8f564d1fe401bd4fd1ba9b4 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.47.0 +2.47.1 -From 842d18f931d475c631983088f0dc68590b5d01f7 Mon Sep 17 00:00:00 2001 +From 9f1e3122d73eb3c58496426357f6db81436a8ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index a1e9b052bc84..ca5193dd1760 100644 +index 09afd75145ed..78953ee8816c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index a1e9b052bc84..ca5193dd1760 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3861,6 +3863,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3867,6 +3869,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index a1e9b052bc84..ca5193dd1760 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0004-ath10k.patch b/patches/6.11/0004-ath10k.patch index 9638e4e61a..3dd87ff333 100644 --- a/patches/6.11/0004-ath10k.patch +++ b/patches/6.11/0004-ath10k.patch @@ -1,4 +1,4 @@ -From bf796a6f659919fc07005a3f592af73bbccec01d Mon Sep 17 00:00:00 2001 +From bfe0767ceac48580c30108ab6daac1c407060901 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index b3294287bce1..2936fdae823c 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0005-ipts.patch b/patches/6.11/0005-ipts.patch index 64096dc1d0..f1a9e920ce 100644 --- a/patches/6.11/0005-ipts.patch +++ b/patches/6.11/0005-ipts.patch @@ -1,4 +1,4 @@ -From 7b55614047170b243dc1c960a58379c8189bc542 Mon Sep 17 00:00:00 2001 +From cf98baee650089d8d322ce941adb508f70e7b8ec Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -35,9 +35,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.47.0 +2.47.1 -From 5232bb39f72e91e8ff1be56bc22967c7be5d5c26 Mon Sep 17 00:00:00 2001 +From ed5408f8d3447fe4a40515abbd6ccbf0aeaad63d Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index e3e513cabc86..d786fbda6eb3 100644 +index cdb8701a968f..d664dde86fcd 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -40,6 +40,11 @@ @@ -91,7 +91,7 @@ index e3e513cabc86..d786fbda6eb3 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -2156,6 +2163,9 @@ static int device_def_domain_type(struct device *dev) +@@ -2168,6 +2175,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index e3e513cabc86..d786fbda6eb3 100644 } return 0; -@@ -2456,6 +2466,9 @@ static int __init init_dmars(void) +@@ -2468,6 +2478,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index e3e513cabc86..d786fbda6eb3 100644 check_tylersburg_isoch(); ret = si_domain_init(hw_pass_through); -@@ -4699,6 +4712,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4713,6 +4726,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index e3e513cabc86..d786fbda6eb3 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4734,6 +4759,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4748,6 +4773,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index e3e513cabc86..d786fbda6eb3 100644 { if (risky_device(dev)) -- -2.47.0 +2.47.1 -From fc25e7b589070e501a5d34a5bbfbc1e54726bb0d Mon Sep 17 00:00:00 2001 +From b96950fbdcba66483f5ce2608a5cc71430c4925b Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3237,5 +3237,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0006-ithc.patch b/patches/6.11/0006-ithc.patch index cd5a3eafec..9c07fdf110 100644 --- a/patches/6.11/0006-ithc.patch +++ b/patches/6.11/0006-ithc.patch @@ -1,4 +1,4 @@ -From 31980f3e712c9d376ed1fbe285fddeebf2f86632 Mon Sep 17 00:00:00 2001 +From 3f81e12dfd2837a046c56c052edc3aabc8ee540e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index e090ca07364b..e575193615bf 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.47.0 +2.47.1 -From 80bbbf9215e6fcd4ab2614b11229b4c2f172effc Mon Sep 17 00:00:00 2001 +From 0762a09dbf4911f892cab58d308c7328e2309ddf Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -2767,5 +2767,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0007-surface-sam.patch b/patches/6.11/0007-surface-sam.patch index c9d536472e..68b5270c89 100644 --- a/patches/6.11/0007-surface-sam.patch +++ b/patches/6.11/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From bf2d9c3afe03fb23296bb163ab83b49534572778 Mon Sep 17 00:00:00 2001 +From 2942ac475f0ec3e0b18bc1bb3432053cd95071dd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -224,9 +224,9 @@ index 000000000000..48c3e826713f +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.47.0 +2.47.1 -From 826d753cfebd01a24a6c8b0b454ab743628511b4 Mon Sep 17 00:00:00 2001 +From 74dc2e2aecbb5d1e9e0ba543ae87ca4708fa5e92 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -419,5 +419,5 @@ index 48c3e826713f..4c08926139db 100644 "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, NULL); -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0008-surface-sam-over-hid.patch b/patches/6.11/0008-surface-sam-over-hid.patch index db844cb0e9..f4fa3f455e 100644 --- a/patches/6.11/0008-surface-sam-over-hid.patch +++ b/patches/6.11/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From aac218684ff18afe0bc296766b4abdaf38c384a5 Mon Sep 17 00:00:00 2001 +From 3b7581a18eb5fe1329200505b20c5b2ff2295ee4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index 14ae0cfc325e..6197c5252d2a 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.47.0 +2.47.1 -From ebcf9444565e3f3050e92cb6b32a8c590bd69189 Mon Sep 17 00:00:00 2001 +From 70118b3481fed555e71e15e3afc19d54648463cd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0009-surface-button.patch b/patches/6.11/0009-surface-button.patch index ff006a5b2d..a90a9a41ed 100644 --- a/patches/6.11/0009-surface-button.patch +++ b/patches/6.11/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 24edbaa278fb632bc77683074b6c7b402f3fe0f2 Mon Sep 17 00:00:00 2001 +From ed528610f8b376e59834d8facc2f3bcde3aa4227 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index 5c5d407fe965..4e1bfe90e730 100644 /* -- -2.47.0 +2.47.1 -From fb78e4db42f1a3c1ed6d8434ab0869f740eeebd9 Mon Sep 17 00:00:00 2001 +From b0202f08273bd8d28bc2652d6d28163a3c20c62d Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0010-surface-typecover.patch b/patches/6.11/0010-surface-typecover.patch index 2397b72c5e..b87b963797 100644 --- a/patches/6.11/0010-surface-typecover.patch +++ b/patches/6.11/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From a5a6bdb95712bac5c7654818ac8d4f057ef4d5cb Mon Sep 17 00:00:00 2001 +From e7b4f40261a112d31be87dacfd756af00cbacf7e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -37,9 +37,9 @@ index 13171454f959..a83beefd25f3 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.47.0 +2.47.1 -From 4ce6ba56469f18617a4498efc9a820eee619adf1 Mon Sep 17 00:00:00 2001 +From 0e5bd25f10026a249ebd03a85a0629957c3cbdd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 847462650549..eea3fdbe28e9 100644 +index 24da73964763..42c393912645 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -257,7 +257,7 @@ index 847462650549..eea3fdbe28e9 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2277,6 +2368,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2290,6 +2381,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -270,9 +270,9 @@ index 847462650549..eea3fdbe28e9 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.47.0 +2.47.1 -From cf0c06dd2575c17fbe7a82e6cc40ffaeea997903 Mon Sep 17 00:00:00 2001 +From a316b2f907765659374f52acf21df1751c1eb371 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -301,7 +301,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index eea3fdbe28e9..382dd01beb82 100644 +index 42c393912645..c44a43db1444 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -569,5 +569,5 @@ index eea3fdbe28e9..382dd01beb82 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0011-surface-shutdown.patch b/patches/6.11/0011-surface-shutdown.patch index 8acbabf2dc..cba0afc4a9 100644 --- a/patches/6.11/0011-surface-shutdown.patch +++ b/patches/6.11/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From f2446b2596fb644a8918c873ee6482a4632a9ed7 Mon Sep 17 00:00:00 2001 +From 44765b95447983e3e02aa26937c6b04266f09461 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -93,5 +93,5 @@ index 37d97bef060f..056fce19477b 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0012-surface-gpe.patch b/patches/6.11/0012-surface-gpe.patch index b9f661c9e8..01f1b4ca09 100644 --- a/patches/6.11/0012-surface-gpe.patch +++ b/patches/6.11/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 9414be4b9e54845ed9f115cda63deb7687b04b38 Mon Sep 17 00:00:00 2001 +From b2ce5736b25f6c6f029c77d95f2d81ea35f8b879 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0013-cameras.patch b/patches/6.11/0013-cameras.patch index 5533f69c74..e2410de9bf 100644 --- a/patches/6.11/0013-cameras.patch +++ b/patches/6.11/0013-cameras.patch @@ -1,4 +1,4 @@ -From 1344a64b467f5d2384e8f9461b31da2ed12160bf Mon Sep 17 00:00:00 2001 +From ea6650d04f5ab12a4985ebb97369ebf01ea40cd0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index 22ae7829a915..0fe281280316 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.47.0 +2.47.1 -From aeb30182901820e1d1be4a0c15c8256212f68a11 Mon Sep 17 00:00:00 2001 +From 00944c91ecce56b317b14bafecc91dabf437647e Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index d786fbda6eb3..3d035ecce4f3 100644 +index d664dde86fcd..9b6f761edbfd 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -45,6 +45,13 @@ @@ -132,7 +132,7 @@ index d786fbda6eb3..3d035ecce4f3 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -2164,6 +2173,9 @@ static int device_def_domain_type(struct device *dev) +@@ -2176,6 +2185,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index d786fbda6eb3..3d035ecce4f3 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2466,6 +2478,9 @@ static int __init init_dmars(void) +@@ -2478,6 +2490,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index d786fbda6eb3..3d035ecce4f3 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4712,6 +4727,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4726,6 +4741,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index d786fbda6eb3..3d035ecce4f3 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4759,6 +4786,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4773,6 +4800,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index d786fbda6eb3..3d035ecce4f3 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.47.0 +2.47.1 -From 6bf250b751177bbaf84ed05dd3bc250ca5cd68e7 Mon Sep 17 00:00:00 2001 +From a5f60bb225cd2d5e75f0c6bfb658a49516d8f0d1 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 1e107fd49f82..e3e1696e7f0e 100644 return 0; -- -2.47.0 +2.47.1 -From 508203342e1ad02fca50a37fe5a8618fa406f13b Mon Sep 17 00:00:00 2001 +From 43afa58f1d17a9b89a13563814342413869d0968 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -275,9 +275,9 @@ index 07b302e09340..baad1e50ca81 100644 agpio, func, polarity); if (ret) -- -2.47.0 +2.47.1 -From b847f014cf9f10674bdd7fd208b5f0c86d0c55ca Mon Sep 17 00:00:00 2001 +From 0427087234f484f6fc57ae685c3189da3fe8a0d8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -314,9 +314,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.47.0 +2.47.1 -From 5db7d52e79618eb92046df0cd0c73f0154f40b92 Mon Sep 17 00:00:00 2001 +From 7babcb1b21ad4297eeddb2c401975b9243639fad Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -365,9 +365,9 @@ index f19c8adf2c61..923ed1b5ab8b 100644 if (ret < 0) goto out_cleanup; -- -2.47.0 +2.47.1 -From bb1c193ae4d1148c3fc944bae4808880350a18d8 Mon Sep 17 00:00:00 2001 +From ad83797e9e55858eb1534145ffaf477aaaf01682 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -406,9 +406,9 @@ index e3e1696e7f0e..423dc555093f 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.47.0 +2.47.1 -From 97b29baa3e74dfb9bf28944228c55b4902606ffd Mon Sep 17 00:00:00 2001 +From 858bebab3db0d2f4481ac7c0d5d52b6cd5534d24 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -447,9 +447,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.47.0 +2.47.1 -From 0c2ad1ee6582ab8d423b082ab0bcf9e5a91868cd Mon Sep 17 00:00:00 2001 +From f3bbef325371ea42bf3de8683a583dee9d3314d4 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -698,9 +698,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.47.0 +2.47.1 -From 80ee359e5cf8405e32b80c3fafbf77e5aa8ce00a Mon Sep 17 00:00:00 2001 +From 8bccdfbc120914eb0364d20b5f2ea82d2a2b3643 Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -745,9 +745,9 @@ index 3df58eb3e882..81aff2d5d898 100644 r = imgu_s_stream(imgu, false); if (!r) -- -2.47.0 +2.47.1 -From 116b355beaaba8bfdb843cea5fb51389571111d1 Mon Sep 17 00:00:00 2001 +From eee949846b8d9fbd5855c45aa1413bb00649d202 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -777,5 +777,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0014-amd-gpio.patch b/patches/6.11/0014-amd-gpio.patch index 5b086d17f4..23018e1162 100644 --- a/patches/6.11/0014-amd-gpio.patch +++ b/patches/6.11/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 80a1c3b9fcc4d2423e528428717a17e112aaf8ca Mon Sep 17 00:00:00 2001 +From 32152c390f4118c40c31ab15936545309d96f077 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 4efecac49863..88377bb0d137 100644 mp_config_acpi_legacy_irqs(); -- -2.47.0 +2.47.1 -From f18c5286b05d2a86f48a86e401e5d04000fad114 Mon Sep 17 00:00:00 2001 +From cbc4937b9a38e01f7209870c115f4f2fea7e9b37 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 88377bb0d137..c58f26918b17 100644 }; -- -2.47.0 +2.47.1 diff --git a/patches/6.11/0015-rtc.patch b/patches/6.11/0015-rtc.patch index 827a8e2f3d..c571e0fd9b 100644 --- a/patches/6.11/0015-rtc.patch +++ b/patches/6.11/0015-rtc.patch @@ -1,4 +1,4 @@ -From 7cbb3d2bc50c08e87fd825e7ae0433307f5152ad Mon Sep 17 00:00:00 2001 +From 574d90399ed8e97d063ac021e74b5e3cece2071a Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index b831cb8e53dc..78bd0f926505 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.47.0 +2.47.1 From 8779c2a543c1b2c5cb59bd19249fa9342b6406dc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 10 Dec 2024 19:55:29 +0100 Subject: [PATCH 069/236] Update Fedora kernels to v6.11.11 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 2663c26fc3..cd37626471 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -18,7 +18,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.11.4-0" +PACKAGE_TAG = "kernel-6.11.11-0" ## ## The release number of the modified kernel package. From 86c80669e15f03d6cba3de3315f62ddc91b03181 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 10 Dec 2024 20:20:06 +0100 Subject: [PATCH 070/236] Add patches for 6.12 Derived from latest 6.11 patches Links: - kernel: https://github.com/linux-surface/kernel/commit/a05cef05d03bcedab4d163a35368dac05762bd8e - tree-devel: https://github.com/linux-surface/kernel/commits/v6.12-surface-devel - tree-patches: https://github.com/linux-surface/kernel/commits/v6.12-surface --- configs/surface-6.12.config | 81 + patches/6.12/0001-secureboot.patch | 112 + patches/6.12/0002-surface3-oemb.patch | 101 + patches/6.12/0003-mwifiex.patch | 400 +++ patches/6.12/0004-ath10k.patch | 120 + patches/6.12/0005-ipts.patch | 3241 ++++++++++++++++++ patches/6.12/0006-ithc.patch | 2771 +++++++++++++++ patches/6.12/0007-surface-sam-over-hid.patch | 308 ++ patches/6.12/0008-surface-button.patch | 149 + patches/6.12/0009-surface-typecover.patch | 575 ++++ patches/6.12/0010-surface-shutdown.patch | 97 + patches/6.12/0011-surface-gpe.patch | 51 + patches/6.12/0012-cameras.patch | 734 ++++ patches/6.12/0013-amd-gpio.patch | 109 + patches/6.12/0014-rtc.patch | 110 + 15 files changed, 8959 insertions(+) create mode 100644 configs/surface-6.12.config create mode 100644 patches/6.12/0001-secureboot.patch create mode 100644 patches/6.12/0002-surface3-oemb.patch create mode 100644 patches/6.12/0003-mwifiex.patch create mode 100644 patches/6.12/0004-ath10k.patch create mode 100644 patches/6.12/0005-ipts.patch create mode 100644 patches/6.12/0006-ithc.patch create mode 100644 patches/6.12/0007-surface-sam-over-hid.patch create mode 100644 patches/6.12/0008-surface-button.patch create mode 100644 patches/6.12/0009-surface-typecover.patch create mode 100644 patches/6.12/0010-surface-shutdown.patch create mode 100644 patches/6.12/0011-surface-gpe.patch create mode 100644 patches/6.12/0012-cameras.patch create mode 100644 patches/6.12/0013-amd-gpio.patch create mode 100644 patches/6.12/0014-rtc.patch diff --git a/configs/surface-6.12.config b/configs/surface-6.12.config new file mode 100644 index 0000000000..05628a9957 --- /dev/null +++ b/configs/surface-6.12.config @@ -0,0 +1,81 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch new file mode 100644 index 0000000000..b21f02c62d --- /dev/null +++ b/patches/6.12/0001-secureboot.patch @@ -0,0 +1,112 @@ +From 7b8f9ca92492dbdc79b474756f95fd0dd8f65404 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.47.1 + +From fce5a218a8239e6fcde688b9dbbad99fb5682062 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index d401577b5a6a..5a812e0b740a 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3066,6 +3066,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index e35829d36039..6d54eb03b63d 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1426,6 +1427,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1484,3 +1491,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.47.1 + diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch new file mode 100644 index 0000000000..089a3372af --- /dev/null +++ b/patches/6.12/0002-surface3-oemb.patch @@ -0,0 +1,101 @@ +From 0f96b7410eade024a604d7295cb2179db8bee6fd Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-oemb +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index c15ed7a12784..1ec8edb5aafa 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.47.1 + diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch new file mode 100644 index 0000000000..6bee4e4260 --- /dev/null +++ b/patches/6.12/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From 6c6251834244fe9265edd4e7af6394ad81052247 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.47.1 + +From c1f2437edf84eb1cff29956ae0ecb57dfdf8b80c Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.47.1 + +From 8ad0cadd6e9207e8ca94e6c703b665074ed4d24f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 4ccaddb46ddd..c583c043e397 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -432,6 +433,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -3813,6 +3815,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.47.1 + diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch new file mode 100644 index 0000000000..dad9c88344 --- /dev/null +++ b/patches/6.12/0004-ath10k.patch @@ -0,0 +1,120 @@ +From 59aa85fc65439e3efa60406453dada3ea02e5045 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index b3294287bce1..2936fdae823c 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.47.1 + diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch new file mode 100644 index 0000000000..709aaf8e71 --- /dev/null +++ b/patches/6.12/0005-ipts.patch @@ -0,0 +1,3241 @@ +From 6a5275171cb4552bcbee07b0c1e3c01e62978449 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6589635f8ba3..a1df48a434e2 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.47.1 + +From b9ead8db37e0ebbec0214d5b8fd7c72ecd8894d3 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index a167d59101ae..f18d5635d2f6 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -40,6 +40,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -2046,6 +2053,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2344,6 +2354,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4649,6 +4662,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4684,6 +4709,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.47.1 + +From 2c0ae9705d84d4215e1b15653026a6e032fb81fc Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index f8a56d631242..38eb29e4cc31 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1373,4 +1373,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + + source "drivers/hid/surface-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 496dab54c73a..02588e5d01eb 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -170,3 +170,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.47.1 + diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch new file mode 100644 index 0000000000..069bbd253c --- /dev/null +++ b/patches/6.12/0006-ithc.patch @@ -0,0 +1,2771 @@ +From dc3bac38912e573c6534082ffcfda0cb2fc9a3e7 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 7a6d188e3bea..0179baee4596 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.47.1 + +From 3dcdddffd167ca72abc56abba9b68e3bfb9d1051 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 38eb29e4cc31..76ad7d9143c7 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1375,4 +1375,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 02588e5d01eb..1ea3d2e0d4e9 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.47.1 + diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch new file mode 100644 index 0000000000..bccbc002c6 --- /dev/null +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From fb90b647af077c040980c0cbe3cfad6721732713 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index 14ae0cfc325e..6197c5252d2a 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.47.1 + +From 6391847801b86a55fb9292d6a984612c757a3a1a Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.47.1 + diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch new file mode 100644 index 0000000000..f9687f71fa --- /dev/null +++ b/patches/6.12/0008-surface-button.patch @@ -0,0 +1,149 @@ +From a4ccd9d3467e16972e6d2b9c1b20ec9c353e6a2d Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index 5c5d407fe965..4e1bfe90e730 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.47.1 + +From d1449ccb8b0e14b6da1a0e37ef1868cfca28dd8e Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.47.1 + diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch new file mode 100644 index 0000000000..77db87029d --- /dev/null +++ b/patches/6.12/0009-surface-typecover.patch @@ -0,0 +1,575 @@ +From 50d5b830735cb753e9c3bf28ce22d5029f20efa9 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 13171454f959..a83beefd25f3 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.47.1 + +From 2fecd84549f58d6bf16716745af3171d24153f47 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e936019d21fe..08fee06fb5fc 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -34,7 +34,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -168,6 +175,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -402,6 +412,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1751,6 +1771,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1774,6 +1857,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1812,8 +1898,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); +@@ -1822,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1873,6 +1963,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2299,6 +2390,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.47.1 + +From 1fc432fe12fdbc07a38271321113f2c8c42668eb Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 08fee06fb5fc..f6664049f46d 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -414,6 +417,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1395,6 +1399,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1422,6 +1429,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1443,6 +1465,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1450,6 +1473,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1459,11 +1495,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1641,6 +1687,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1689,6 +1771,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1771,30 +1860,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1803,8 +1868,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1941,13 +2007,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1956,12 +2033,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.47.1 + diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch new file mode 100644 index 0000000000..7b52d59317 --- /dev/null +++ b/patches/6.12/0010-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 0bbdd7d2db381178371df106dab5bb87826731b9 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 35270172c833..529779994ef6 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index dccb60c1d9cc..7baec2d30547 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6298,3 +6298,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 573b4c4c2be6..237178ff25b4 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -467,6 +467,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.47.1 + diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch new file mode 100644 index 0000000000..92289bbdbc --- /dev/null +++ b/patches/6.12/0011-surface-gpe.patch @@ -0,0 +1,51 @@ +From cb15b7cff81b20563d02bb6067fe7cfa41657e13 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index 62fd4004db31..103fc4468262 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.47.1 + diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch new file mode 100644 index 0000000000..f277a38858 --- /dev/null +++ b/patches/6.12/0012-cameras.patch @@ -0,0 +1,734 @@ +From c1e732d74af13fa185e6628c0b3450d7a78c3771 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 7ecc401fb97f..e35185de1902 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.47.1 + +From 0aa7b46ca0715e55cfa1dafd27465b344bdbd509 Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index f18d5635d2f6..361f4c178efb 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -45,6 +45,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -214,12 +221,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -2054,6 +2063,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2354,6 +2366,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4662,6 +4677,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4709,6 +4736,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.47.1 + +From 034be5df2dd7dc9ccf7d03c437b50a9fca5909cd Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 1e107fd49f82..e3e1696e7f0e 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.47.1 + +From 69facb79bc2f03538ff5b96193d2794b2d1cc920 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 3de463c3d13b..0a012eeed30a 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ { } ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity ^= GPIO_ACTIVE_LOW; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) +-- +2.47.1 + +From 85500807eba9230225365c9ffa41ae25adb26d5c Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.47.1 + +From 07e189e6fa0d9d409f4668c952300163c10b9658 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index f19c8adf2c61..923ed1b5ab8b 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.47.1 + +From 4d876396a289e66f0934a9d06e1c8ace2e6c1921 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index e3e1696e7f0e..423dc555093f 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.47.1 + +From 5c47116cc76fa1d282fdb80ab848ec9c2f9c0c07 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.47.1 + +From 020153866ecdf79f5ab24cf1d572624c823b963e Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index b784bb74a837..f8d8fcfacac2 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -941,6 +941,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 18afbb5a23ee..a1d16c0af82d 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.47.1 + +From c56c16bb3c2764e1ebda60becb78286a24f0b108 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.47.1 + diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch new file mode 100644 index 0000000000..8ce3021514 --- /dev/null +++ b/patches/6.12/0013-amd-gpio.patch @@ -0,0 +1,109 @@ +From 7205903c398ebd99315a4570b42708d425278912 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 4efecac49863..88377bb0d137 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.47.1 + +From f7dea61de13087c4ef2f3afdfee883e3907d24f5 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 88377bb0d137..c58f26918b17 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.47.1 + diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch new file mode 100644 index 0000000000..5828594c3a --- /dev/null +++ b/patches/6.12/0014-rtc.patch @@ -0,0 +1,110 @@ +From a05cef05d03bcedab4d163a35368dac05762bd8e Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index b831cb8e53dc..78bd0f926505 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.47.1 + From 6f49fedc2f429175e4275451ecef145c582e8fbc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 10 Dec 2024 20:25:36 +0100 Subject: [PATCH 071/236] Update Arch kernel to v6.12.4 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3-oemb.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- .../kernel/0007-surface-sam-over-hid.patch | 1 + pkg/arch/kernel/0007-surface-sam.patch | 1 - pkg/arch/kernel/0008-surface-button.patch | 1 + .../kernel/0008-surface-sam-over-hid.patch | 1 - pkg/arch/kernel/0009-surface-button.patch | 1 - pkg/arch/kernel/0009-surface-typecover.patch | 1 + pkg/arch/kernel/0010-surface-shutdown.patch | 1 + pkg/arch/kernel/0010-surface-typecover.patch | 1 - pkg/arch/kernel/0011-surface-gpe.patch | 1 + pkg/arch/kernel/0011-surface-shutdown.patch | 1 - pkg/arch/kernel/0012-cameras.patch | 1 + pkg/arch/kernel/0012-surface-gpe.patch | 1 - pkg/arch/kernel/0013-amd-gpio.patch | 1 + pkg/arch/kernel/0013-cameras.patch | 1 - pkg/arch/kernel/0014-amd-gpio.patch | 1 - pkg/arch/kernel/0014-rtc.patch | 1 + pkg/arch/kernel/0015-rtc.patch | 1 - pkg/arch/kernel/PKGBUILD | 52 +++-- pkg/arch/kernel/config | 187 ++++++++++++------ pkg/arch/kernel/surface.config | 2 +- 26 files changed, 166 insertions(+), 104 deletions(-) create mode 120000 pkg/arch/kernel/0007-surface-sam-over-hid.patch delete mode 120000 pkg/arch/kernel/0007-surface-sam.patch create mode 120000 pkg/arch/kernel/0008-surface-button.patch delete mode 120000 pkg/arch/kernel/0008-surface-sam-over-hid.patch delete mode 120000 pkg/arch/kernel/0009-surface-button.patch create mode 120000 pkg/arch/kernel/0009-surface-typecover.patch create mode 120000 pkg/arch/kernel/0010-surface-shutdown.patch delete mode 120000 pkg/arch/kernel/0010-surface-typecover.patch create mode 120000 pkg/arch/kernel/0011-surface-gpe.patch delete mode 120000 pkg/arch/kernel/0011-surface-shutdown.patch create mode 120000 pkg/arch/kernel/0012-cameras.patch delete mode 120000 pkg/arch/kernel/0012-surface-gpe.patch create mode 120000 pkg/arch/kernel/0013-amd-gpio.patch delete mode 120000 pkg/arch/kernel/0013-cameras.patch delete mode 120000 pkg/arch/kernel/0014-amd-gpio.patch create mode 120000 pkg/arch/kernel/0014-rtc.patch delete mode 120000 pkg/arch/kernel/0015-rtc.patch diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 686f88ee6e..5f9c78e8d0 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.11/0001-secureboot.patch \ No newline at end of file +../../../patches/6.12/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3-oemb.patch b/pkg/arch/kernel/0002-surface3-oemb.patch index f8442119ab..3ab3eddcb5 120000 --- a/pkg/arch/kernel/0002-surface3-oemb.patch +++ b/pkg/arch/kernel/0002-surface3-oemb.patch @@ -1 +1 @@ -../../../patches/6.11/0002-surface3-oemb.patch \ No newline at end of file +../../../patches/6.12/0002-surface3-oemb.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index 47a2aa6d8a..d39603075b 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.11/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.12/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index 0a9abad8fd..d0bc43e2c2 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.11/0004-ath10k.patch \ No newline at end of file +../../../patches/6.12/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index e9cc5e8f56..383c962da1 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.11/0005-ipts.patch \ No newline at end of file +../../../patches/6.12/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index f981cd94f2..ed8f03666c 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.11/0006-ithc.patch \ No newline at end of file +../../../patches/6.12/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam-over-hid.patch b/pkg/arch/kernel/0007-surface-sam-over-hid.patch new file mode 120000 index 0000000000..e67edaf50a --- /dev/null +++ b/pkg/arch/kernel/0007-surface-sam-over-hid.patch @@ -0,0 +1 @@ +../../../patches/6.12/0007-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch deleted file mode 120000 index 340b8182a3..0000000000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-button.patch b/pkg/arch/kernel/0008-surface-button.patch new file mode 120000 index 0000000000..5fa465409e --- /dev/null +++ b/pkg/arch/kernel/0008-surface-button.patch @@ -0,0 +1 @@ +../../../patches/6.12/0008-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch deleted file mode 120000 index c9b7dbe548..0000000000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch deleted file mode 120000 index f0ce82afbc..0000000000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-typecover.patch b/pkg/arch/kernel/0009-surface-typecover.patch new file mode 120000 index 0000000000..5020908f2a --- /dev/null +++ b/pkg/arch/kernel/0009-surface-typecover.patch @@ -0,0 +1 @@ +../../../patches/6.12/0009-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-shutdown.patch b/pkg/arch/kernel/0010-surface-shutdown.patch new file mode 120000 index 0000000000..1392efb661 --- /dev/null +++ b/pkg/arch/kernel/0010-surface-shutdown.patch @@ -0,0 +1 @@ +../../../patches/6.12/0010-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch deleted file mode 120000 index 663d576c91..0000000000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-gpe.patch b/pkg/arch/kernel/0011-surface-gpe.patch new file mode 120000 index 0000000000..2ea93f4800 --- /dev/null +++ b/pkg/arch/kernel/0011-surface-gpe.patch @@ -0,0 +1 @@ +../../../patches/6.12/0011-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch deleted file mode 120000 index 97d2f21a58..0000000000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-cameras.patch b/pkg/arch/kernel/0012-cameras.patch new file mode 120000 index 0000000000..d29732717e --- /dev/null +++ b/pkg/arch/kernel/0012-cameras.patch @@ -0,0 +1 @@ +../../../patches/6.12/0012-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch deleted file mode 120000 index ffc9db7603..0000000000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-amd-gpio.patch b/pkg/arch/kernel/0013-amd-gpio.patch new file mode 120000 index 0000000000..4b9166a735 --- /dev/null +++ b/pkg/arch/kernel/0013-amd-gpio.patch @@ -0,0 +1 @@ +../../../patches/6.12/0013-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch deleted file mode 120000 index 38e7b8ebd1..0000000000 --- a/pkg/arch/kernel/0013-cameras.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch deleted file mode 120000 index 83eb5d9f1b..0000000000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-rtc.patch b/pkg/arch/kernel/0014-rtc.patch new file mode 120000 index 0000000000..1d6c7da4e7 --- /dev/null +++ b/pkg/arch/kernel/0014-rtc.patch @@ -0,0 +1 @@ +../../../patches/6.12/0014-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch deleted file mode 120000 index f1c8b5a1e7..0000000000 --- a/pkg/arch/kernel/0015-rtc.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.11/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index e1ef72be8e..19441a23f9 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.11.4.arch1 +pkgver=6.12.4.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -42,40 +42,38 @@ source=( 0004-ath10k.patch 0005-ipts.patch 0006-ithc.patch - 0007-surface-sam.patch - 0008-surface-sam-over-hid.patch - 0009-surface-button.patch - 0010-surface-typecover.patch - 0011-surface-shutdown.patch - 0012-surface-gpe.patch - 0013-cameras.patch - 0014-amd-gpio.patch - 0015-rtc.patch + 0007-surface-sam-over-hid.patch + 0008-surface-button.patch + 0009-surface-typecover.patch + 0010-surface-shutdown.patch + 0011-surface-gpe.patch + 0012-cameras.patch + 0013-amd-gpio.patch + 0014-rtc.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('6927373ee4edaaba5f62b0f998afc8afdce9f65b1d3c3ba4da88cbcc8f85d308' - '85d7da72a3bfb175caa71ec26393f32c3ac7457477f53be373a94192392caef6' +sha256sums=('ee49835f0acfdb3c9f205a49762f30bacd4c49b3aef72a4928f794fe9f4a17e7' + 'a6a234cd982d21f0d7daa3ba921293e450abd87ff5d7474d4a153b3f34cfabc5' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '5cfe5d045942fab6dbe0de852f6beabd5dfcf8d811ce7055f58487d62fae565e' - '257e3a056eee9c4daa203aca3a96cbff6b352663117550e13b64214e6a0e288d' - '6c7f360e4e5a3c1821aef1f67fe64e7b998fefdf8a67cbe8878756e8190c1ad0' - '3abfbfdd256c8b500b6b4a44e14e8948336e1fe585b26feba20a3cfc5612d354' - 'febffd7d115851ff6974c9624be6781c1cece7ad10492e7e6b0068c3a67a28b3' - '90acb7dd407d0d189050f67a14ce885384fb66dfd72ce03a87e07964f53bf005' - '91bf57fb58aa135211475128177b492a47246f4cb100dfe66da705886bd10fce' - '675cdaaed10c0bd0582612098159eab5dea9a1b8ee872236f11ad3fb8c920588' - '80b2dc9f7a060a9c9bac596dd1444ca4b7c21492037f72b113640c3c7aacb356' - 'b4ca88151a4b79f46303c25db5f4fd7c9fceacf7466118516dfe223c9797c46b' - 'f0b5ada4756b425881aca1fa17bb8415c74fc48d5ead36e8e2980d19dcfaa5b3' - '4aaebeb14b51eb96cb569da194c688774082e6028b183029356f71d261d3c295' - '99973b6f85dede6e2b658d39b0f8aef1ed1513d4fbd1db36cb6124e2cf3790cb' - '4daa5d8a227bbe9534ae2610113ead66fffa77f46a377de5e88ecfa83928b46a' - '313841d4c3d4cb0a9bec758b40e4364fcfe0c3258ab78a723489076d25894b9a') + '4a2f0955f0ff8f59f3177645290cd140093dbbf16ad284bb2c66605bce51abd9' + '693ad9f38925a8f7a5f1599d53ddb6d9bce0f88f8856fe44b5718ffdaae5484e' + '7444b3dd59bcb331a8254ba77e078733c6e1aed5b1f468c46f70d1cd602af40d' + 'e38da94144737e89e9cadfab19e79b9f70333df8fe4a17fc82d08767fde42d9c' + '80cd33e27bf4c0fdd79835d781ee1b421016fddb5028585ac8c6d2eeb8ed2c22' + '2bb1c50797d04e11c30ad8b10acf4d5e0beec8ea380704515b9068d122161079' + '463cb4f28f3fe4149a1bfcdeed63e1165cc87cd955d5cedb23245518bfa448e6' + 'f37067910f37d16a1b34c7c48e217a9bb54954390e73fc1018471c8f8f56c577' + '51589b43cde5ed3b2cd625422a3f2ab971080fc0630f899d3c184404f3ca16bc' + 'edabebf0615daf61d1b7a47acd94fa3ecbab5c2082e166d513f0a131d01ba446' + 'd3dab0de90456637bb22d7beac9773a545ac2c4383adc0014976ee45d62a7ca7' + 'cf02f26570b2ff3584d95f9d9512f2e08563507fc89fd4a0c14d0edc0365a91c' + '6f6f1a57f47a2a9db01b39693c7450ec86efcf8623b2100a183bc9bd0f8b5510' + '6d56d0efadefa150cd4f459f42bee00a60ec32a4ace66013278ec72c76bfca6b') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index ea28db1d73..456086c376 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.11.4-arch1 Kernel Configuration +# Linux/x86 6.12.4-arch1 Kernel Configuration # CONFIG_CC_VERSION_TEXT="gcc (GCC) 14.2.1 20240910" CONFIG_CC_IS_GCC=y @@ -11,6 +11,8 @@ CONFIG_AS_VERSION=24300 CONFIG_LD_IS_BFD=y CONFIG_LD_VERSION=24300 CONFIG_LLD_VERSION=0 +CONFIG_RUSTC_VERSION=0 +CONFIG_RUSTC_LLVM_VERSION=0 CONFIG_CC_CAN_LINK=y CONFIG_CC_CAN_LINK_STATIC=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y @@ -137,6 +139,7 @@ CONFIG_PREEMPT_COUNT=y CONFIG_PREEMPTION=y CONFIG_PREEMPT_DYNAMIC=y CONFIG_SCHED_CORE=y +CONFIG_SCHED_CLASS_EXT=y # # CPU/Task time and stats accounting @@ -223,9 +226,11 @@ CONFIG_MEMCG=y CONFIG_BLK_CGROUP=y CONFIG_CGROUP_WRITEBACK=y CONFIG_CGROUP_SCHED=y +CONFIG_GROUP_SCHED_WEIGHT=y CONFIG_FAIR_GROUP_SCHED=y CONFIG_CFS_BANDWIDTH=y # CONFIG_RT_GROUP_SCHED is not set +CONFIG_EXT_GROUP_SCHED=y CONFIG_SCHED_MM_CID=y CONFIG_UCLAMP_TASK_GROUP=y CONFIG_CGROUP_PIDS=y @@ -233,6 +238,7 @@ CONFIG_CGROUP_RDMA=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_HUGETLB=y CONFIG_CPUSETS=y +# CONFIG_CPUSETS_V1 is not set CONFIG_PROC_PID_CPUSET=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y @@ -432,11 +438,11 @@ CONFIG_HPET_EMULATE_RTC=y CONFIG_DMI=y # CONFIG_GART_IOMMU is not set CONFIG_BOOT_VESA_SUPPORT=y -# CONFIG_MAXSMP is not set -CONFIG_NR_CPUS_RANGE_BEGIN=2 -CONFIG_NR_CPUS_RANGE_END=512 -CONFIG_NR_CPUS_DEFAULT=64 -CONFIG_NR_CPUS=320 +CONFIG_MAXSMP=y +CONFIG_NR_CPUS_RANGE_BEGIN=8192 +CONFIG_NR_CPUS_RANGE_END=8192 +CONFIG_NR_CPUS_DEFAULT=8192 +CONFIG_NR_CPUS=8192 CONFIG_SCHED_CLUSTER=y CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y @@ -479,8 +485,7 @@ CONFIG_AMD_MEM_ENCRYPT=y CONFIG_NUMA=y CONFIG_AMD_NUMA=y CONFIG_X86_64_ACPI_NUMA=y -# CONFIG_NUMA_EMU is not set -CONFIG_NODES_SHIFT=5 +CONFIG_NODES_SHIFT=10 CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_DEFAULT=y # CONFIG_ARCH_MEMORY_PROBE is not set @@ -495,12 +500,12 @@ CONFIG_MTRR_SANITIZER=y CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=0 CONFIG_X86_PAT=y -CONFIG_ARCH_USES_PG_UNCACHED=y CONFIG_X86_UMIP=y CONFIG_CC_HAS_IBT=y CONFIG_X86_CET=y CONFIG_X86_KERNEL_IBT=y CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y +CONFIG_ARCH_PKEY_BITS=4 # CONFIG_X86_INTEL_TSX_MODE_OFF is not set # CONFIG_X86_INTEL_TSX_MODE_ON is not set CONFIG_X86_INTEL_TSX_MODE_AUTO=y @@ -526,6 +531,7 @@ CONFIG_ARCH_SUPPORTS_KEXEC_SIG_FORCE=y CONFIG_ARCH_SUPPORTS_KEXEC_BZIMAGE_VERIFY_SIG=y CONFIG_ARCH_SUPPORTS_KEXEC_JUMP=y CONFIG_ARCH_SUPPORTS_CRASH_DUMP=y +CONFIG_ARCH_DEFAULT_CRASH_DUMP=y CONFIG_ARCH_SUPPORTS_CRASH_HOTPLUG=y CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION=y CONFIG_PHYSICAL_START=0x1000000 @@ -536,7 +542,6 @@ CONFIG_PHYSICAL_ALIGN=0x200000 CONFIG_DYNAMIC_MEMORY_LAYOUT=y CONFIG_RANDOMIZE_MEMORY=y CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa -CONFIG_ADDRESS_MASKING=y CONFIG_HOTPLUG_CPU=y # CONFIG_COMPAT_VDSO is not set CONFIG_LEGACY_VSYSCALL_XONLY=y @@ -571,9 +576,18 @@ CONFIG_MITIGATION_IBPB_ENTRY=y CONFIG_MITIGATION_IBRS_ENTRY=y CONFIG_MITIGATION_SRSO=y CONFIG_MITIGATION_SLS=y -# CONFIG_MITIGATION_GDS_FORCE is not set +CONFIG_MITIGATION_GDS=y CONFIG_MITIGATION_RFDS=y CONFIG_MITIGATION_SPECTRE_BHI=y +CONFIG_MITIGATION_MDS=y +CONFIG_MITIGATION_TAA=y +CONFIG_MITIGATION_MMIO_STALE_DATA=y +CONFIG_MITIGATION_L1TF=y +CONFIG_MITIGATION_RETBLEED=y +CONFIG_MITIGATION_SPECTRE_V1=y +CONFIG_MITIGATION_SPECTRE_V2=y +CONFIG_MITIGATION_SRBDS=y +CONFIG_MITIGATION_SSB=y CONFIG_ARCH_HAS_ADD_PAGES=y # @@ -786,6 +800,7 @@ CONFIG_KVM_GENERIC_PRIVATE_MEM=y CONFIG_HAVE_KVM_ARCH_GMEM_PREPARE=y CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE=y CONFIG_VIRTUALIZATION=y +CONFIG_KVM_X86=m CONFIG_KVM=m CONFIG_KVM_INTEL=m CONFIG_X86_SGX_KVM=y @@ -805,6 +820,7 @@ CONFIG_AS_VAES=y CONFIG_AS_VPCLMULQDQ=y CONFIG_AS_WRUSS=y CONFIG_ARCH_CONFIGURES_CPU_MITIGATIONS=y +CONFIG_ARCH_HAS_DMA_OPS=y # # General architecture-dependent options @@ -868,6 +884,7 @@ CONFIG_MMU_GATHER_RCU_TABLE_FREE=y CONFIG_MMU_GATHER_MERGE_VMAS=y CONFIG_MMU_LAZY_TLB_REFCOUNT=y CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_ARCH_HAVE_EXTRA_ELF_NOTES=y CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y CONFIG_HAVE_CMPXCHG_LOCAL=y @@ -929,6 +946,7 @@ CONFIG_ISA_BUS_API=y CONFIG_OLD_SIGSUSPEND3=y CONFIG_COMPAT_OLD_SIGACTION=y CONFIG_COMPAT_32BIT_TIME=y +CONFIG_ARCH_SUPPORTS_RT=y CONFIG_HAVE_ARCH_VMAP_STACK=y CONFIG_VMAP_STACK=y CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y @@ -996,10 +1014,11 @@ CONFIG_MODULE_SIG_SHA512=y # CONFIG_MODULE_SIG_SHA3_384 is not set # CONFIG_MODULE_SIG_SHA3_512 is not set CONFIG_MODULE_SIG_HASH="sha512" -# CONFIG_MODULE_COMPRESS_NONE is not set +CONFIG_MODULE_COMPRESS=y # CONFIG_MODULE_COMPRESS_GZIP is not set # CONFIG_MODULE_COMPRESS_XZ is not set CONFIG_MODULE_COMPRESS_ZSTD=y +CONFIG_MODULE_COMPRESS_ALL=y CONFIG_MODULE_DECOMPRESS=y CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y CONFIG_MODPROBE_PATH="/sbin/modprobe" @@ -1105,7 +1124,7 @@ CONFIG_COREDUMP=y CONFIG_ZPOOL=y CONFIG_SWAP=y CONFIG_ZSWAP=y -CONFIG_ZSWAP_DEFAULT_ON=y +# CONFIG_ZSWAP_DEFAULT_ON is not set CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y # CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set # CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO is not set @@ -1118,9 +1137,8 @@ CONFIG_ZSWAP_COMPRESSOR_DEFAULT="zstd" # CONFIG_ZSWAP_ZPOOL_DEFAULT_Z3FOLD_DEPRECATED is not set CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC=y CONFIG_ZSWAP_ZPOOL_DEFAULT="zsmalloc" -CONFIG_ZBUD=y +CONFIG_ZBUD=m # CONFIG_Z3FOLD_DEPRECATED is not set -CONFIG_HAVE_ZSMALLOC=y CONFIG_ZSMALLOC=y CONFIG_ZSMALLOC_STAT=y CONFIG_ZSMALLOC_CHAIN_SIZE=8 @@ -1158,8 +1176,9 @@ CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_MHP_MEMMAP_ON_MEMORY=y CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y -CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SPLIT_PTE_PTLOCKS=y CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y +CONFIG_SPLIT_PMD_PTLOCKS=y CONFIG_MEMORY_BALLOON=y CONFIG_BALLOON_COMPACTION=y CONFIG_COMPACTION=y @@ -1187,6 +1206,9 @@ CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y CONFIG_THP_SWAP=y CONFIG_READ_ONLY_THP_FOR_FS=y CONFIG_PGTABLE_HAS_HUGE_LEAVES=y +CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP=y +CONFIG_ARCH_SUPPORTS_PMD_PFNMAP=y +CONFIG_ARCH_SUPPORTS_PUD_PFNMAP=y CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_USE_PERCPU_NUMA_NODE_ID=y @@ -1212,6 +1234,7 @@ CONFIG_DEVICE_PRIVATE=y CONFIG_VMAP_PFN=y CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y CONFIG_ARCH_HAS_PKEYS=y +CONFIG_ARCH_USES_PG_ARCH_2=y CONFIG_VM_EVENT_COUNTERS=y # CONFIG_PERCPU_STATS is not set # CONFIG_GUP_TEST is not set @@ -1234,6 +1257,8 @@ CONFIG_PER_VMA_LOCK=y CONFIG_LOCK_MM_AND_FIND_VMA=y CONFIG_IOMMU_MM_DATA=y CONFIG_EXECMEM=y +CONFIG_NUMA_MEMBLKS=y +# CONFIG_NUMA_EMU is not set # # Data Access Monitoring @@ -1256,6 +1281,7 @@ CONFIG_NET_XGRESS=y CONFIG_NET_REDIRECT=y CONFIG_SKB_DECRYPTED=y CONFIG_SKB_EXTENSIONS=y +CONFIG_NET_DEVMEM=y # # Networking options @@ -2027,7 +2053,6 @@ CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_CMTP=m CONFIG_BT_HIDP=m CONFIG_BT_LE=y CONFIG_BT_LE_L2CAP_ECRED=y @@ -2067,6 +2092,7 @@ CONFIG_BT_HCIUART_RTL=y CONFIG_BT_HCIUART_QCA=y CONFIG_BT_HCIUART_AG6XX=y CONFIG_BT_HCIUART_MRVL=y +CONFIG_BT_HCIUART_AML=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBCM4377=m CONFIG_BT_HCIBPA10X=m @@ -2138,6 +2164,7 @@ CONFIG_NET_9P=m CONFIG_NET_9P_FD=m CONFIG_NET_9P_VIRTIO=m CONFIG_NET_9P_XEN=m +CONFIG_NET_9P_USBG=y CONFIG_NET_9P_RDMA=m # CONFIG_NET_9P_DEBUG is not set # CONFIG_CAIF is not set @@ -2241,6 +2268,7 @@ CONFIG_PCI_ATS=y CONFIG_PCI_DOE=y CONFIG_PCI_LOCKLESS_CONFIG=y CONFIG_PCI_IOV=y +CONFIG_PCI_NPEM=y CONFIG_PCI_PRI=y CONFIG_PCI_PASID=y CONFIG_PCI_P2PDMA=y @@ -2633,11 +2661,18 @@ CONFIG_BLK_DEV_FD=m CONFIG_CDROM=m CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m CONFIG_ZRAM=m +CONFIG_ZRAM_BACKEND_LZ4=y +CONFIG_ZRAM_BACKEND_LZ4HC=y +CONFIG_ZRAM_BACKEND_ZSTD=y +CONFIG_ZRAM_BACKEND_DEFLATE=y +CONFIG_ZRAM_BACKEND_842=y +CONFIG_ZRAM_BACKEND_LZO=y # CONFIG_ZRAM_DEF_COMP_LZORLE is not set -CONFIG_ZRAM_DEF_COMP_ZSTD=y -# CONFIG_ZRAM_DEF_COMP_LZ4 is not set # CONFIG_ZRAM_DEF_COMP_LZO is not set +# CONFIG_ZRAM_DEF_COMP_LZ4 is not set # CONFIG_ZRAM_DEF_COMP_LZ4HC is not set +CONFIG_ZRAM_DEF_COMP_ZSTD=y +# CONFIG_ZRAM_DEF_COMP_DEFLATE is not set # CONFIG_ZRAM_DEF_COMP_842 is not set CONFIG_ZRAM_DEF_COMP="zstd" CONFIG_ZRAM_WRITEBACK=y @@ -2704,6 +2739,7 @@ CONFIG_AD525X_DPOT_SPI=m # CONFIG_DUMMY_IRQ is not set CONFIG_IBM_ASM=m CONFIG_PHANTOM=m +CONFIG_RPMB=m CONFIG_TIFM_CORE=m CONFIG_TIFM_7XX1=m CONFIG_ICS932S401=m @@ -3447,6 +3483,7 @@ CONFIG_MLX5_MACSEC=y CONFIG_MLX5_EN_IPSEC=y CONFIG_MLX5_EN_TLS=y CONFIG_MLX5_SW_STEERING=y +CONFIG_MLX5_HW_STEERING=y CONFIG_MLX5_SF=y CONFIG_MLX5_SF_MANAGER=y CONFIG_MLX5_DPLL=m @@ -3471,6 +3508,7 @@ CONFIG_ENC28J60=m # CONFIG_ENC28J60_WRITEVERIFY is not set CONFIG_ENCX24J600=m CONFIG_LAN743X=m +CONFIG_LAN865X=m CONFIG_VCAP=y CONFIG_NET_VENDOR_MICROSEMI=y CONFIG_MSCC_OCELOT_SWITCH_LIB=m @@ -3501,6 +3539,7 @@ CONFIG_NET_VENDOR_NVIDIA=y CONFIG_FORCEDETH=m CONFIG_NET_VENDOR_OKI=y CONFIG_ETHOC=m +CONFIG_OA_TC6=m CONFIG_NET_VENDOR_PACKET_ENGINES=y CONFIG_HAMACHI=m CONFIG_YELLOWFIN=m @@ -3538,6 +3577,7 @@ CONFIG_8139TOO_8129=y # CONFIG_8139_OLD_RX_RESET is not set CONFIG_R8169=m CONFIG_R8169_LEDS=y +CONFIG_RTASE=m CONFIG_NET_VENDOR_RENESAS=y CONFIG_NET_VENDOR_ROCKER=y CONFIG_ROCKER=m @@ -3620,6 +3660,7 @@ CONFIG_PHYLINK=m CONFIG_PHYLIB=m CONFIG_SWPHY=y CONFIG_LED_TRIGGER_PHY=y +CONFIG_OPEN_ALLIANCE_HELPERS=y CONFIG_FIXED_PHY=m CONFIG_SFP=m @@ -3703,6 +3744,7 @@ CONFIG_CAN_C_CAN=m CONFIG_CAN_C_CAN_PLATFORM=m CONFIG_CAN_C_CAN_PCI=m CONFIG_CAN_CC770=m +CONFIG_CAN_CC770_ISA=m CONFIG_CAN_CC770_PLATFORM=m CONFIG_CAN_CTUCANFD=m CONFIG_CAN_CTUCANFD_PCI=m @@ -3722,6 +3764,7 @@ CONFIG_CAN_PEAK_PCI=m CONFIG_CAN_PEAK_PCIEC=y CONFIG_CAN_PEAK_PCMCIA=m CONFIG_CAN_PLX_PCI=m +CONFIG_CAN_SJA1000_ISA=m CONFIG_CAN_SJA1000_PLATFORM=m CONFIG_CAN_SOFTING=m CONFIG_CAN_SOFTING_CS=m @@ -4151,11 +4194,13 @@ CONFIG_RTW89_8851B=m CONFIG_RTW89_8852A=m CONFIG_RTW89_8852B_COMMON=m CONFIG_RTW89_8852B=m +CONFIG_RTW89_8852BT=m CONFIG_RTW89_8852C=m CONFIG_RTW89_8922A=m CONFIG_RTW89_8851BE=m CONFIG_RTW89_8852AE=m CONFIG_RTW89_8852BE=m +CONFIG_RTW89_8852BTE=m CONFIG_RTW89_8852CE=m CONFIG_RTW89_8922AE=m CONFIG_RTW89_DEBUG=y @@ -4225,8 +4270,6 @@ CONFIG_NETDEVSIM=m CONFIG_NET_FAILOVER=m CONFIG_ISDN=y CONFIG_ISDN_CAPI=y -CONFIG_CAPI_TRACE=y -CONFIG_ISDN_CAPI_MIDDLEWARE=y CONFIG_MISDN=m CONFIG_MISDN_DSP=m CONFIG_MISDN_L1OIP=m @@ -4290,7 +4333,6 @@ CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_LM8323=m CONFIG_KEYBOARD_LM8333=m CONFIG_KEYBOARD_MAX7359=m -CONFIG_KEYBOARD_MCS=m CONFIG_KEYBOARD_MPR121=m CONFIG_KEYBOARD_NEWTON=m CONFIG_KEYBOARD_OPENCORES=m @@ -4398,9 +4440,6 @@ CONFIG_TOUCHSCREEN_CY8CTMG110=m CONFIG_TOUCHSCREEN_CYTTSP_CORE=m CONFIG_TOUCHSCREEN_CYTTSP_I2C=m CONFIG_TOUCHSCREEN_CYTTSP_SPI=m -CONFIG_TOUCHSCREEN_CYTTSP4_CORE=m -CONFIG_TOUCHSCREEN_CYTTSP4_I2C=m -CONFIG_TOUCHSCREEN_CYTTSP4_SPI=m CONFIG_TOUCHSCREEN_CYTTSP5=m CONFIG_TOUCHSCREEN_DA9034=m CONFIG_TOUCHSCREEN_DA9052=m @@ -4427,7 +4466,6 @@ CONFIG_TOUCHSCREEN_ELO=m CONFIG_TOUCHSCREEN_WACOM_W8001=m CONFIG_TOUCHSCREEN_WACOM_I2C=m CONFIG_TOUCHSCREEN_MAX11801=m -CONFIG_TOUCHSCREEN_MCS5000=m CONFIG_TOUCHSCREEN_MMS114=m CONFIG_TOUCHSCREEN_MELFAS_MIP4=m CONFIG_TOUCHSCREEN_MSG2638=m @@ -4752,7 +4790,6 @@ CONFIG_XILLYUSB=m CONFIG_I2C=y CONFIG_ACPI_I2C_OPREGION=y CONFIG_I2C_BOARDINFO=y -CONFIG_I2C_COMPAT=y CONFIG_I2C_CHARDEV=m CONFIG_I2C_MUX=m @@ -4820,6 +4857,7 @@ CONFIG_I2C_DESIGNWARE_PCI=y CONFIG_I2C_EMEV2=m CONFIG_I2C_GPIO=m # CONFIG_I2C_GPIO_FAULT_INJECTOR is not set +CONFIG_I2C_KEBA=m CONFIG_I2C_KEMPLD=m CONFIG_I2C_OCORES=m CONFIG_I2C_PCA_PLATFORM=m @@ -5177,7 +5215,6 @@ CONFIG_POWER_RESET_MT6323=y CONFIG_POWER_RESET_RESTART=y CONFIG_POWER_RESET_TPS65086=y CONFIG_POWER_SEQUENCING=m -CONFIG_POWER_SEQUENCING_QCOM_WCN=m CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set CONFIG_POWER_SUPPLY_HWMON=y @@ -5498,6 +5535,7 @@ CONFIG_SENSORS_SCH5627=m CONFIG_SENSORS_SCH5636=m CONFIG_SENSORS_STTS751=m CONFIG_SENSORS_SURFACE_FAN=m +CONFIG_SENSORS_SURFACE_TEMP=m CONFIG_SENSORS_ADC128D818=m CONFIG_SENSORS_ADS7828=m CONFIG_SENSORS_ADS7871=m @@ -5549,6 +5587,7 @@ CONFIG_THERMAL=y CONFIG_THERMAL_NETLINK=y # CONFIG_THERMAL_STATISTICS is not set # CONFIG_THERMAL_DEBUGFS is not set +CONFIG_THERMAL_CORE_TESTING=m CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=100 CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y @@ -6016,6 +6055,7 @@ CONFIG_CEC_CROS_EC=m CONFIG_CEC_GPIO=m CONFIG_CEC_SECO=m CONFIG_CEC_SECO_RC=y +CONFIG_USB_EXTRON_DA_HD_4K_PLUS_CEC=m CONFIG_USB_PULSE8_CEC=m CONFIG_USB_RAINSHADOW_CEC=m # end of CEC support @@ -6868,6 +6908,11 @@ CONFIG_DRM_MIPI_DBI=m CONFIG_DRM_MIPI_DSI=y # CONFIG_DRM_DEBUG_MM is not set CONFIG_DRM_KMS_HELPER=y +CONFIG_DRM_PANIC=y +CONFIG_DRM_PANIC_FOREGROUND_COLOR=0xffffff +CONFIG_DRM_PANIC_BACKGROUND_COLOR=0x0000aa +# CONFIG_DRM_PANIC_DEBUG is not set +CONFIG_DRM_PANIC_SCREEN="kmsg" CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_FBDEV_OVERALLOC=100 CONFIG_DRM_LOAD_EDID_FIRMWARE=y @@ -7087,6 +7132,7 @@ CONFIG_FB_SYS_IMAGEBLIT=y CONFIG_FB_SYSMEM_FOPS=y CONFIG_FB_DEFERRED_IO=y CONFIG_FB_DMAMEM_HELPERS=y +CONFIG_FB_DMAMEM_HELPERS_DEFERRED=y CONFIG_FB_IOMEM_FOPS=y CONFIG_FB_IOMEM_HELPERS=y CONFIG_FB_SYSMEM_HELPERS=y @@ -7200,7 +7246,6 @@ CONFIG_SND_MAX_CARDS=32 # CONFIG_SND_SUPPORT_OLD_API is not set CONFIG_SND_PROC_FS=y CONFIG_SND_VERBOSE_PROCFS=y -CONFIG_SND_VERBOSE_PRINTK=y CONFIG_SND_CTL_FAST_LOOKUP=y CONFIG_SND_DEBUG=y # CONFIG_SND_DEBUG_VERBOSE is not set @@ -7208,6 +7253,7 @@ CONFIG_SND_DEBUG=y CONFIG_SND_CTL_INPUT_VALIDATION=y # CONFIG_SND_CTL_DEBUG is not set # CONFIG_SND_JACK_INJECTION_DEBUG is not set +CONFIG_SND_UTIMER=y CONFIG_SND_VMASTER=y CONFIG_SND_DMA_SGBUF=y CONFIG_SND_CTL_LED=m @@ -7420,6 +7466,7 @@ CONFIG_SND_SOC_AMD_ACP6x=m CONFIG_SND_SOC_AMD_YC_MACH=m CONFIG_SND_AMD_ACP_CONFIG=m CONFIG_SND_SOC_AMD_ACP_COMMON=m +CONFIG_SND_SOC_ACPI_AMD_MATCH=m CONFIG_SND_SOC_AMD_ACP_PDM=m CONFIG_SND_SOC_AMD_ACP_LEGACY_COMMON=m CONFIG_SND_SOC_AMD_ACP_I2S=m @@ -7432,6 +7479,7 @@ CONFIG_SND_AMD_ASOC_ACP70=m CONFIG_SND_SOC_AMD_MACH_COMMON=m CONFIG_SND_SOC_AMD_LEGACY_MACH=m CONFIG_SND_SOC_AMD_SOF_MACH=m +CONFIG_SND_SOC_AMD_SOF_SDW_MACH=m CONFIG_SND_AMD_SOUNDWIRE_ACPI=m CONFIG_SND_SOC_AMD_RPL_ACP6x=m CONFIG_SND_SOC_AMD_ACP63_TOPLEVEL=m @@ -7473,24 +7521,10 @@ CONFIG_SND_SOC_IMG_SPDIF_IN=m CONFIG_SND_SOC_IMG_SPDIF_OUT=m CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC=m CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y -CONFIG_SND_SOC_INTEL_SST=m CONFIG_SND_SOC_INTEL_CATPT=m CONFIG_SND_SST_ATOM_HIFI2_PLATFORM=m CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI=m CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI=m -CONFIG_SND_SOC_INTEL_SKYLAKE=m -CONFIG_SND_SOC_INTEL_SKL=m -CONFIG_SND_SOC_INTEL_APL=m -CONFIG_SND_SOC_INTEL_KBL=m -CONFIG_SND_SOC_INTEL_GLK=m -CONFIG_SND_SOC_INTEL_CNL=m -CONFIG_SND_SOC_INTEL_CFL=m -CONFIG_SND_SOC_INTEL_CML_H=m -CONFIG_SND_SOC_INTEL_CML_LP=m -CONFIG_SND_SOC_INTEL_SKYLAKE_FAMILY=m -CONFIG_SND_SOC_INTEL_SKYLAKE_SSP_CLK=m -CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC=y -CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON=m CONFIG_SND_SOC_ACPI_INTEL_MATCH=m CONFIG_SND_SOC_INTEL_AVS=m @@ -7543,18 +7577,7 @@ CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH=m CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH=m CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH=m # CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set -CONFIG_SND_SOC_INTEL_SKL_RT286_MACH=m -CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH=m -CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH=m -CONFIG_SND_SOC_INTEL_DA7219_MAX98357A_GENERIC=m -CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH=m -CONFIG_SND_SOC_INTEL_BXT_RT298_MACH=m CONFIG_SND_SOC_INTEL_SOF_WM8804_MACH=m -CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH=m -CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH=m -CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH=m -CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH=m -CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH=m CONFIG_SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH=m CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH=m CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH=m @@ -7590,6 +7613,7 @@ CONFIG_SND_SOC_SOF_ACP_PROBES=m CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE=m CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE=m CONFIG_SND_SOC_SOF_AMD_ACP63=m +CONFIG_SND_SOC_SOF_AMD_ACP70=m CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL=y CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC=m CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP=m @@ -7617,6 +7641,8 @@ CONFIG_SND_SOC_SOF_INTEL_MTL=m CONFIG_SND_SOC_SOF_METEORLAKE=m CONFIG_SND_SOC_SOF_INTEL_LNL=m CONFIG_SND_SOC_SOF_LUNARLAKE=m +CONFIG_SND_SOC_SOF_INTEL_PTL=m +CONFIG_SND_SOC_SOF_PANTHERLAKE=m CONFIG_SND_SOC_SOF_HDA_COMMON=m CONFIG_SND_SOC_SOF_HDA_GENERIC=m CONFIG_SND_SOC_SOF_HDA_MLINK=m @@ -7740,7 +7766,6 @@ CONFIG_SND_SOC_ES8328=m CONFIG_SND_SOC_ES8328_I2C=m CONFIG_SND_SOC_ES8328_SPI=m CONFIG_SND_SOC_GTM601=m -CONFIG_SND_SOC_HDAC_HDMI=m CONFIG_SND_SOC_HDAC_HDA=m CONFIG_SND_SOC_HDA=m CONFIG_SND_SOC_ICS43432=m @@ -7798,7 +7823,6 @@ CONFIG_SND_SOC_RT1316_SDW=m CONFIG_SND_SOC_RT1318_SDW=m CONFIG_SND_SOC_RT1320_SDW=m CONFIG_SND_SOC_RT5514=m -CONFIG_SND_SOC_RT5514_SPI=m CONFIG_SND_SOC_RT5616=m CONFIG_SND_SOC_RT5631=m CONFIG_SND_SOC_RT5640=m @@ -7925,6 +7949,7 @@ CONFIG_SND_SOC_WSA884X=m CONFIG_SND_SOC_ZL38060=m CONFIG_SND_SOC_MAX9759=m CONFIG_SND_SOC_MT6351=m +CONFIG_SND_SOC_MT6357=m CONFIG_SND_SOC_MT6358=m CONFIG_SND_SOC_MT6660=m CONFIG_SND_SOC_NAU8315=m @@ -7942,6 +7967,7 @@ CONFIG_SND_SOC_LPASS_RX_MACRO=m CONFIG_SND_SOC_LPASS_TX_MACRO=m # end of CODEC drivers +CONFIG_SND_SOC_SDW_UTILS=m CONFIG_SND_SIMPLE_CARD_UTILS=m CONFIG_SND_SIMPLE_CARD=m CONFIG_SND_X86=y @@ -7996,6 +8022,7 @@ CONFIG_HID_GLORIOUS=m CONFIG_HID_HOLTEK=m CONFIG_HOLTEK_FF=y CONFIG_HID_VIVALDI_COMMON=m +CONFIG_HID_GOODIX_SPI=m CONFIG_HID_GOOGLE_HAMMER=m CONFIG_HID_GOOGLE_STADIA_FF=m CONFIG_HID_VIVALDI=m @@ -8167,7 +8194,7 @@ CONFIG_USB_MON=m CONFIG_USB_C67X00_HCD=m CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DBGCAP=y -CONFIG_USB_XHCI_PCI=m +CONFIG_USB_XHCI_PCI=y CONFIG_USB_XHCI_PCI_RENESAS=m CONFIG_USB_XHCI_PLATFORM=m CONFIG_USB_EHCI_HCD=y @@ -8676,6 +8703,7 @@ CONFIG_LEDS_IS31FL319X=m # LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) # CONFIG_LEDS_BLINKM=m +CONFIG_LEDS_BLINKM_MULTICOLOR=y CONFIG_LEDS_MLXCPLD=m CONFIG_LEDS_MLXREG=m CONFIG_LEDS_USER=m @@ -8885,6 +8913,7 @@ CONFIG_RTC_DRV_EM3027=m CONFIG_RTC_DRV_RV3028=m CONFIG_RTC_DRV_RV3032=m CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_SD2405AL=m CONFIG_RTC_DRV_SD3078=m # @@ -8979,6 +9008,7 @@ CONFIG_INTEL_IOATDMA=m CONFIG_PLX_DMA=m CONFIG_XILINX_DMA=m CONFIG_XILINX_XDMA=m +CONFIG_AMD_QDMA=m CONFIG_AMD_PTDMA=m CONFIG_QCOM_HIDMA_MGMT=m CONFIG_QCOM_HIDMA=m @@ -9224,7 +9254,6 @@ CONFIG_MOST_COMPONENTS=m CONFIG_MOST_NET=m CONFIG_MOST_VIDEO=m CONFIG_MOST_I2C=m -CONFIG_KS7010=m CONFIG_FIELDBUS_DEV=m # CONFIG_VME_BUS is not set # CONFIG_GOLDFISH is not set @@ -9634,6 +9663,7 @@ CONFIG_EXTCON_GPIO=m CONFIG_EXTCON_INTEL_INT3496=m CONFIG_EXTCON_INTEL_CHT_WC=m CONFIG_EXTCON_INTEL_MRFLD=m +CONFIG_EXTCON_LC824206XA=m CONFIG_EXTCON_MAX14577=m CONFIG_EXTCON_MAX3355=m CONFIG_EXTCON_MAX77693=m @@ -9682,6 +9712,9 @@ CONFIG_ADXL367_I2C=m CONFIG_ADXL372=m CONFIG_ADXL372_SPI=m CONFIG_ADXL372_I2C=m +CONFIG_ADXL380=m +CONFIG_ADXL380_SPI=m +CONFIG_ADXL380_I2C=m CONFIG_BMA220=m CONFIG_BMA400=m CONFIG_BMA400_I2C=m @@ -9734,7 +9767,9 @@ CONFIG_STK8BA50=m # Analog to digital converters # CONFIG_AD_SIGMA_DELTA=m +CONFIG_AD4000=m CONFIG_AD4130=m +CONFIG_AD4695=m CONFIG_AD7091R=m CONFIG_AD7091R5=m CONFIG_AD7091R8=m @@ -9798,6 +9833,7 @@ CONFIG_MEDIATEK_MT6370_ADC=m CONFIG_MEN_Z188_ADC=m CONFIG_MP2629_ADC=m CONFIG_NAU7802=m +CONFIG_PAC1921=m CONFIG_PAC1934=m CONFIG_PALMAS_GPADC=m CONFIG_RICHTEK_RTQ6056=m @@ -9949,6 +9985,7 @@ CONFIG_DPOT_DAC=m CONFIG_DS4424=m CONFIG_LTC1660=m CONFIG_LTC2632=m +CONFIG_LTC2664=m CONFIG_M62332=m CONFIG_MAX517=m CONFIG_MAX5522=m @@ -10043,6 +10080,7 @@ CONFIG_MAX30102=m # CONFIG_AM2315=m CONFIG_DHT11=m +CONFIG_ENS210=m CONFIG_HDC100X=m CONFIG_HDC2010=m CONFIG_HDC3020=m @@ -10104,6 +10142,7 @@ CONFIG_APDS9300=m CONFIG_APDS9306=m CONFIG_APDS9960=m CONFIG_AS73211=m +CONFIG_BH1745=m CONFIG_BH1750=m CONFIG_BH1780=m CONFIG_CM32181=m @@ -10265,6 +10304,7 @@ CONFIG_MS5611=m CONFIG_MS5611_I2C=m CONFIG_MS5611_SPI=m CONFIG_MS5637=m +CONFIG_SDP500=m CONFIG_IIO_ST_PRESS=m CONFIG_IIO_ST_PRESS_I2C=m CONFIG_IIO_ST_PRESS_SPI=m @@ -10285,6 +10325,7 @@ CONFIG_AS3935=m # Proximity and distance sensors # CONFIG_CROS_EC_MKBP_PROXIMITY=m +CONFIG_HX9023S=m CONFIG_IRSD200=m CONFIG_ISL29501=m CONFIG_LIDAR_LITE_V2=m @@ -10300,6 +10341,7 @@ CONFIG_SX9500=m CONFIG_SRF08=m CONFIG_VCNL3020=m CONFIG_VL53L0X_I2C=m +CONFIG_AW96103=m # end of Proximity and distance sensors # @@ -10419,6 +10461,7 @@ CONFIG_RAS=y CONFIG_RAS_CEC=y # CONFIG_RAS_CEC_DEBUG is not set CONFIG_AMD_ATL=m +CONFIG_AMD_ATL_PRM=y CONFIG_RAS_FMPM=m CONFIG_USB4=m # CONFIG_USB4_DEBUGFS_WRITE is not set @@ -10611,6 +10654,7 @@ CONFIG_BCACHEFS_POSIX_ACL=y CONFIG_BCACHEFS_LOCK_TIME_STATS=y # CONFIG_BCACHEFS_NO_LATENCY_ACCT is not set CONFIG_BCACHEFS_SIX_OPTIMISTIC_SPIN=y +# CONFIG_BCACHEFS_PATH_TRACEPOINTS is not set CONFIG_ZONEFS_FS=m CONFIG_FS_DAX=y CONFIG_FS_DAX_PMD=y @@ -10713,6 +10757,7 @@ CONFIG_HUGETLBFS=y # CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set CONFIG_HUGETLB_PAGE=y CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y +CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING=y CONFIG_ARCH_HAS_GIGANTIC_PAGE=y CONFIG_CONFIGFS_FS=y CONFIG_EFIVAR_FS=y @@ -10802,6 +10847,7 @@ CONFIG_EROFS_FS=m CONFIG_EROFS_FS_XATTR=y CONFIG_EROFS_FS_POSIX_ACL=y CONFIG_EROFS_FS_SECURITY=y +CONFIG_EROFS_FS_BACKED_BY_FILE=y CONFIG_EROFS_FS_ZIP=y CONFIG_EROFS_FS_ZIP_LZMA=y CONFIG_EROFS_FS_ZIP_DEFLATE=y @@ -10847,6 +10893,8 @@ CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_NFS_ACL_SUPPORT=m CONFIG_NFS_COMMON=y +CONFIG_NFS_COMMON_LOCALIO_SUPPORT=m +CONFIG_NFS_LOCALIO=y CONFIG_NFS_V4_2_SSC_HELPER=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m @@ -10875,6 +10923,7 @@ CONFIG_CIFS_DFS_UPCALL=y CONFIG_CIFS_SWN_UPCALL=y CONFIG_CIFS_SMB_DIRECT=y CONFIG_CIFS_FSCACHE=y +CONFIG_CIFS_COMPRESSION=y CONFIG_SMB_SERVER=m CONFIG_SMB_SERVER_SMBDIRECT=y CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN=y @@ -11012,6 +11061,20 @@ CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE=y # CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY is not set # CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY is not set CONFIG_SECURITY_LANDLOCK=y +CONFIG_SECURITY_IPE=y +CONFIG_IPE_BOOT_POLICY="" +CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING=y +CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING=y + +# +# IPE Trust Providers +# +CONFIG_IPE_PROP_DM_VERITY=y +CONFIG_IPE_PROP_DM_VERITY_SIGNATURE=y +CONFIG_IPE_PROP_FS_VERITY=y +CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG=y +# end of IPE Trust Providers + CONFIG_INTEGRITY=y CONFIG_INTEGRITY_SIGNATURE=y CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y @@ -11426,7 +11489,9 @@ CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y CONFIG_XZ_DEC_ARM=y CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_ARM64=y CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_RISCV=y CONFIG_XZ_DEC_MICROLZMA=y CONFIG_XZ_DEC_BCJ=y # CONFIG_XZ_DEC_TEST is not set @@ -11456,7 +11521,7 @@ CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_IOPORT_MAP=y CONFIG_HAS_DMA=y -CONFIG_DMA_OPS=y +CONFIG_DMA_OPS_HELPERS=y CONFIG_NEED_SG_DMA_FLAGS=y CONFIG_NEED_SG_DMA_LENGTH=y CONFIG_NEED_DMA_MAP_STATE=y @@ -11482,6 +11547,7 @@ CONFIG_CMA_ALIGNMENT=8 # CONFIG_DMA_MAP_BENCHMARK is not set CONFIG_SGL_ALLOC=y CONFIG_CHECK_SIGNATURE=y +CONFIG_CPUMASK_OFFSTACK=y CONFIG_CPU_RMAP=y CONFIG_DQL=y CONFIG_GLOB=y @@ -11647,8 +11713,6 @@ CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y # CONFIG_DEBUG_VIRTUAL is not set CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_DEBUG_PER_CPU_MAPS is not set -CONFIG_ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP=y -# CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP is not set # CONFIG_MEM_ALLOC_PROFILING is not set CONFIG_HAVE_ARCH_KASAN=y CONFIG_HAVE_ARCH_KASAN_VMALLOC=y @@ -11893,6 +11957,7 @@ CONFIG_RUNTIME_TESTING_MENU=y # CONFIG_LKDTM is not set # CONFIG_TEST_MIN_HEAP is not set # CONFIG_TEST_DIV64 is not set +# CONFIG_TEST_MULDIV64 is not set # CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_TEST_REF_TRACKER is not set # CONFIG_RBTREE_TEST is not set diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index 334f7098f2..bc3c4bde54 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.10.config \ No newline at end of file +../../../configs/surface-6.12.config \ No newline at end of file From 4cc9905f268b368003c80d8cf557e8de52c680fd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 10 Dec 2024 20:26:36 +0100 Subject: [PATCH 072/236] Update Debian kernel to v6.12.3 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 6d91e8f96a..a1b258dda6 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.10.10" +KERNEL_VERSION="6.12.3" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From a08b1579139a87cc1c0d0579863240c2e0d803b5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 12 Dec 2024 00:11:52 +0100 Subject: [PATCH 073/236] pkg/debian: Fix disabling of module compression for v6.12 kernels --- pkg/debian/kernel/ubuntu.config | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/debian/kernel/ubuntu.config b/pkg/debian/kernel/ubuntu.config index 64ad8192a9..137419756b 100644 --- a/pkg/debian/kernel/ubuntu.config +++ b/pkg/debian/kernel/ubuntu.config @@ -12,10 +12,7 @@ CONFIG_DEBUG_INFO_NONE=y ## ## Disable module compression ## -CONFIG_MODULE_COMPRESS_NONE=y -# CONFIG_MODULE_COMPRESS_GZIP is not set -# CONFIG_MODULE_COMPRESS_XZ is not set -# CONFIG_MODULE_COMPRESS_ZSTD is not set +# CONFIG_MODULE_COMPRESS is not set ## ## Do not build samples and tests From 821307dcaa06069112496e021fb48cc1c8691a95 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 12 Dec 2024 00:12:10 +0100 Subject: [PATCH 074/236] pkg/debian: Bump release --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index a1b258dda6..9a0c4ee86d 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ KERNEL_VERSION="6.12.3" -KERNEL_REVISION="1" +KERNEL_REVISION="2" KERNEL_LOCALVERSION="-surface" From f94e8003ac27fcbc22a5d08114e4fe024700ab0e Mon Sep 17 00:00:00 2001 From: Benjamin Otto Date: Sun, 22 Dec 2024 14:19:45 +0100 Subject: [PATCH 075/236] Build Fedora in Actions without Secure boot (#1616) --- pkg/fedora/kernel-surface/build-linux-surface.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index cd37626471..413c988b8d 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -4,6 +4,7 @@ import subprocess import sys from pathlib import Path +import logging ##################################################################### @@ -86,7 +87,7 @@ # Check if the major version is supported. if not patches.exists() or not config.exists(): - print("ERROR: Could not find patches / configs for kernel %s!" % kernel_major) + logging.error("ERROR: Could not find patches / configs for kernel %s!" % kernel_major) sys.exit(1) # Check if Secure Boot keys are available. @@ -94,12 +95,11 @@ # If we are building without secureboot, require user input to continue. if not sb_avail: - print("") - print("Secure Boot keys were not configured! Using Red Hat testkeys.") - print("The compiled kernel will not boot with Secure Boot enabled!") - print("") + logging.warning("Secure Boot keys were not configured! Using Red Hat testkeys.") + logging.warning("The compiled kernel will not boot with Secure Boot enabled!") - input("Press enter to continue: ") + if sys.stdin.isatty(): + input("Press enter to continue: ") # Expand globs surface_patches = sorted(patches.glob("*.patch")) From f1ae1aa85c5e182126e5777a23702fb15084c1d6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Dec 2024 04:21:24 +0100 Subject: [PATCH 076/236] Update v6.12 patches Changes: - Rebase onto v6.12.7 Links: - kernel: https://github.com/linux-surface/kernel/commit/a05cef05d03bcedab4d163a35368dac05762bd8e --- patches/6.12/0001-secureboot.patch | 4 +-- patches/6.12/0002-surface3-oemb.patch | 2 +- patches/6.12/0003-mwifiex.patch | 10 ++++---- patches/6.12/0004-ath10k.patch | 2 +- patches/6.12/0005-ipts.patch | 12 ++++----- patches/6.12/0006-ithc.patch | 4 +-- patches/6.12/0007-surface-sam-over-hid.patch | 4 +-- patches/6.12/0008-surface-button.patch | 4 +-- patches/6.12/0009-surface-typecover.patch | 6 ++--- patches/6.12/0010-surface-shutdown.patch | 8 +++--- patches/6.12/0011-surface-gpe.patch | 2 +- patches/6.12/0012-cameras.patch | 26 ++++++++++---------- patches/6.12/0013-amd-gpio.patch | 4 +-- patches/6.12/0014-rtc.patch | 2 +- 14 files changed, 45 insertions(+), 45 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index b21f02c62d..addb86e813 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 7b8f9ca92492dbdc79b474756f95fd0dd8f65404 Mon Sep 17 00:00:00 2001 +From bbcfb18eb05bd92e4501ca35bdfd558c849ddeda Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index b5c79f43359b..a1bbedd989e4 100644 -- 2.47.1 -From fce5a218a8239e6fcde688b9dbbad99fb5682062 Mon Sep 17 00:00:00 2001 +From 9a796344897d077f1fc977ab026315c2cfcd3960 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index 089a3372af..ab40dd606c 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 0f96b7410eade024a604d7295cb2179db8bee6fd Mon Sep 17 00:00:00 2001 +From 2ce5cf2a597c9015c64ea9f386a396f97b8589c6 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index 6bee4e4260..523a943588 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 6c6251834244fe9265edd4e7af6394ad81052247 Mon Sep 17 00:00:00 2001 +From ed54461506b98c1bc8ae8dc5f7385de1f900ed0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.47.1 -From c1f2437edf84eb1cff29956ae0ecb57dfdf8b80c Mon Sep 17 00:00:00 2001 +From a93a869673e056cf2a2c46b9438edaca8f5e2645 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.47.1 -From 8ad0cadd6e9207e8ca94e6c703b665074ed4d24f Mon Sep 17 00:00:00 2001 +From bcc616a02ed2a9e059d2e7a1dd5b5289412efcbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 4ccaddb46ddd..c583c043e397 100644 +index 11755cb1eb16..e69c6c9957a2 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 4ccaddb46ddd..c583c043e397 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3813,6 +3815,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3837,6 +3839,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index dad9c88344..e1e6253a8b 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 59aa85fc65439e3efa60406453dada3ea02e5045 Mon Sep 17 00:00:00 2001 +From cc9a74a369def421de56b0581f6131c4cd15355d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index 709aaf8e71..0e4a8c8176 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From 6a5275171cb4552bcbee07b0c1e3c01e62978449 Mon Sep 17 00:00:00 2001 +From 3e89507b8f6c6d36e5bf587a74c65be5d9796ffd Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 6589635f8ba3..a1df48a434e2 100644 -- 2.47.1 -From b9ead8db37e0ebbec0214d5b8fd7c72ecd8894d3 Mon Sep 17 00:00:00 2001 +From 1d6df5a556693e735cc78a603c29112a76ee883b Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index a167d59101ae..f18d5635d2f6 100644 +index cc23cfcdeb2d..c010aebe6cc1 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -40,6 +40,11 @@ @@ -111,7 +111,7 @@ index a167d59101ae..f18d5635d2f6 100644 check_tylersburg_isoch(); /* -@@ -4649,6 +4662,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4651,6 +4664,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index a167d59101ae..f18d5635d2f6 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4684,6 +4709,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4686,6 +4711,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -144,7 +144,7 @@ index a167d59101ae..f18d5635d2f6 100644 -- 2.47.1 -From 2c0ae9705d84d4215e1b15653026a6e032fb81fc Mon Sep 17 00:00:00 2001 +From e4e616d49f7a021b83cd0114f0642090e88a054f Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index 069bbd253c..ecc37aa866 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From dc3bac38912e573c6534082ffcfda0cb2fc9a3e7 Mon Sep 17 00:00:00 2001 +From d07e07e448b9b1ac7102911263626b623f138a28 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 7a6d188e3bea..0179baee4596 100644 -- 2.47.1 -From 3dcdddffd167ca72abc56abba9b68e3bfb9d1051 Mon Sep 17 00:00:00 2001 +From 280c63dff160b59d1cbac71a63dc7f16d335fec9 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index bccbc002c6..a65acd8e4f 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From fb90b647af077c040980c0cbe3cfad6721732713 Mon Sep 17 00:00:00 2001 +From 064893f3e33bd77cecece7ea4047b3a6e1147fe2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index 14ae0cfc325e..6197c5252d2a 100644 -- 2.47.1 -From 6391847801b86a55fb9292d6a984612c757a3a1a Mon Sep 17 00:00:00 2001 +From f6714cb9a95aeec3379336df70e7cc8d9537f727 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index f9687f71fa..934e9156d2 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From a4ccd9d3467e16972e6d2b9c1b20ec9c353e6a2d Mon Sep 17 00:00:00 2001 +From 9d06bf6cc92b13c9e4c4781484b82804c4150d80 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index 5c5d407fe965..4e1bfe90e730 100644 -- 2.47.1 -From d1449ccb8b0e14b6da1a0e37ef1868cfca28dd8e Mon Sep 17 00:00:00 2001 +From f870bb021693abb7ea617c323216c615151b62e1 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index 77db87029d..de3cb8160d 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From 50d5b830735cb753e9c3bf28ce22d5029f20efa9 Mon Sep 17 00:00:00 2001 +From df8f9981df6f0a92100266397ded155314efc7e3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 13171454f959..a83beefd25f3 100644 -- 2.47.1 -From 2fecd84549f58d6bf16716745af3171d24153f47 Mon Sep 17 00:00:00 2001 +From 3aa9fc5fd7faed0bd5948e80e6ef6173c32a83ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index e936019d21fe..08fee06fb5fc 100644 -- 2.47.1 -From 1fc432fe12fdbc07a38271321113f2c8c42668eb Mon Sep 17 00:00:00 2001 +From c88ebc0ed1f21ec7ad52aa4fb2c48226603d7596 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index 7b52d59317..9194e85fe8 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 0bbdd7d2db381178371df106dab5bb87826731b9 Mon Sep 17 00:00:00 2001 +From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -37,10 +37,10 @@ index 35270172c833..529779994ef6 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index dccb60c1d9cc..7baec2d30547 100644 +index 8103bc24a54e..e8fa8d810925 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6298,3 +6298,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6301,3 +6301,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -81,7 +81,7 @@ index dccb60c1d9cc..7baec2d30547 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 573b4c4c2be6..237178ff25b4 100644 +index 4e77c4230c0a..a4b0e6ef6cfe 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -467,6 +467,7 @@ struct pci_dev { diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index 92289bbdbc..cb83acb03c 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From cb15b7cff81b20563d02bb6067fe7cfa41657e13 Mon Sep 17 00:00:00 2001 +From 8120dc21068acfe547e9c6d1cced417e5931c7ad Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index f277a38858..64014fd030 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From c1e732d74af13fa185e6628c0b3450d7a78c3771 Mon Sep 17 00:00:00 2001 +From 2cb3cbe91cb78a8747e6eee341c1d4e20c459d16 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index 7ecc401fb97f..e35185de1902 100644 -- 2.47.1 -From 0aa7b46ca0715e55cfa1dafd27465b344bdbd509 Mon Sep 17 00:00:00 2001 +From 29efdd823d22e0a6f7dead43d9c309602a1d2cbd Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index f18d5635d2f6..361f4c178efb 100644 +index c010aebe6cc1..42b342184d56 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -45,6 +45,13 @@ @@ -152,7 +152,7 @@ index f18d5635d2f6..361f4c178efb 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4662,6 +4677,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4664,6 +4679,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index f18d5635d2f6..361f4c178efb 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4709,6 +4736,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4711,6 +4738,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -184,7 +184,7 @@ index f18d5635d2f6..361f4c178efb 100644 -- 2.47.1 -From 034be5df2dd7dc9ccf7d03c437b50a9fca5909cd Mon Sep 17 00:00:00 2001 +From 503ddf1a3c915d4b1108b44a280fd588fd11252c Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 1e107fd49f82..e3e1696e7f0e 100644 -- 2.47.1 -From 69facb79bc2f03538ff5b96193d2794b2d1cc920 Mon Sep 17 00:00:00 2001 +From 46806f2df854794beb466026561dc6446ec77632 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -277,7 +277,7 @@ index 3de463c3d13b..0a012eeed30a 100644 -- 2.47.1 -From 85500807eba9230225365c9ffa41ae25adb26d5c Mon Sep 17 00:00:00 2001 +From af26f5acd84f8f7db95873690902562a159a94fb Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -316,7 +316,7 @@ index 30f61e04ecaf..9c1292ca8552 100644 -- 2.47.1 -From 07e189e6fa0d9d409f4668c952300163c10b9658 Mon Sep 17 00:00:00 2001 +From d0bcf0400f018b7d505f47bcf21ef7843f1372ca Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -367,7 +367,7 @@ index f19c8adf2c61..923ed1b5ab8b 100644 -- 2.47.1 -From 4d876396a289e66f0934a9d06e1c8ace2e6c1921 Mon Sep 17 00:00:00 2001 +From 222586440493b857e7c5aa363f8741b7fff753be Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -408,7 +408,7 @@ index e3e1696e7f0e..423dc555093f 100644 -- 2.47.1 -From 5c47116cc76fa1d282fdb80ab848ec9c2f9c0c07 Mon Sep 17 00:00:00 2001 +From b0e450741669b478b74d8610fd9dbae817962077 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -449,7 +449,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.47.1 -From 020153866ecdf79f5ab24cf1d572624c823b963e Mon Sep 17 00:00:00 2001 +From 7f546475ba781cf67aedd9817046b506873edab1 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -700,7 +700,7 @@ index 000000000000..35aeb5db89c8 -- 2.47.1 -From c56c16bb3c2764e1ebda60becb78286a24f0b108 Mon Sep 17 00:00:00 2001 +From adf794d65cca167d5bc66ef0c8a160e3fbeb3481 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index 8ce3021514..93c8956a23 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From 7205903c398ebd99315a4570b42708d425278912 Mon Sep 17 00:00:00 2001 +From 28b8120e4f9b02ec49ccedd036557552a1aee5dc Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 4efecac49863..88377bb0d137 100644 -- 2.47.1 -From f7dea61de13087c4ef2f3afdfee883e3907d24f5 Mon Sep 17 00:00:00 2001 +From 1b801d759aced457e5508cf931fa849400233b92 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index 5828594c3a..784921d06d 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From a05cef05d03bcedab4d163a35368dac05762bd8e Mon Sep 17 00:00:00 2001 +From 0a6b868f61d7564bc898ac30c84fbf3c34fb7368 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From b432f336d5156dba25168f3e43b76f57ad345c86 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Dec 2024 04:23:05 +0100 Subject: [PATCH 077/236] Update Arch kernel to v6.12.7 --- pkg/arch/kernel/PKGBUILD | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 19441a23f9..d229b2faf9 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.12.4.arch1 +pkgver=6.12.7.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -56,24 +56,24 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('ee49835f0acfdb3c9f205a49762f30bacd4c49b3aef72a4928f794fe9f4a17e7' +sha256sums=('0fd0d052ca0b649ed6e12ca883ca9bdf49bd35c60372e4c34fe24019c442466a' 'a6a234cd982d21f0d7daa3ba921293e450abd87ff5d7474d4a153b3f34cfabc5' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '4a2f0955f0ff8f59f3177645290cd140093dbbf16ad284bb2c66605bce51abd9' - '693ad9f38925a8f7a5f1599d53ddb6d9bce0f88f8856fe44b5718ffdaae5484e' - '7444b3dd59bcb331a8254ba77e078733c6e1aed5b1f468c46f70d1cd602af40d' - 'e38da94144737e89e9cadfab19e79b9f70333df8fe4a17fc82d08767fde42d9c' - '80cd33e27bf4c0fdd79835d781ee1b421016fddb5028585ac8c6d2eeb8ed2c22' - '2bb1c50797d04e11c30ad8b10acf4d5e0beec8ea380704515b9068d122161079' - '463cb4f28f3fe4149a1bfcdeed63e1165cc87cd955d5cedb23245518bfa448e6' - 'f37067910f37d16a1b34c7c48e217a9bb54954390e73fc1018471c8f8f56c577' - '51589b43cde5ed3b2cd625422a3f2ab971080fc0630f899d3c184404f3ca16bc' - 'edabebf0615daf61d1b7a47acd94fa3ecbab5c2082e166d513f0a131d01ba446' - 'd3dab0de90456637bb22d7beac9773a545ac2c4383adc0014976ee45d62a7ca7' - 'cf02f26570b2ff3584d95f9d9512f2e08563507fc89fd4a0c14d0edc0365a91c' - '6f6f1a57f47a2a9db01b39693c7450ec86efcf8623b2100a183bc9bd0f8b5510' - '6d56d0efadefa150cd4f459f42bee00a60ec32a4ace66013278ec72c76bfca6b') + '979c23063ac85900deb62d6ab54f250bab5f9bae83dbe4082145b86772570dff' + 'eef74faedb785a3b484909b820d447b793b0b2d6eaf1aecc3ab9ee94a9ece48e' + '9284772ff36b0389b60cfeddab3a378ecb57ae1420183b87c71266a87def787d' + '93631c1e0670c5a6e185b136bbe21866be6be7648ca0a969e90a9fb337c70214' + '5d5a75e191e76a79100566ca7e96e4de45430fddd3d195ad78da5966499903b1' + 'd5e9d28884dc5b651d8d4e69e2798be3d1fdea9fba3da63007fa373a1bb1eb7e' + '7f1cda3bba5d8e8349f0d2524d502571170d4e2ef9204c41f9ebe705ada627cc' + '845a2045280e4725d925767dd3098700b45f85035c0a5072cc81a77178235223' + '16549d3d4f461e0f11d954e70a626ae319760fba2e10cf2f4804a670b1b7a418' + 'bb042ae3aedceb366785e8043e67e77dce19c0ae0e558ddae1bea0c50603848c' + '2dd074e9ba0f380fe5334d809e98fc351b07a533b7bc7d36cbd357e7fadea784' + 'df6c27af42db207a19c0c69210af6f4c26070d16989dd833dfebd80ac3990b17' + '0109e2dfa394f9918a5b73fbe98c634e05413f257ad19cc78c73baacd9f04ea5' + 'b247a7aa0f9f9d844dc7c8fba438b9abb845b89da161c498ae72d2d62bcdbeb0') export KBUILD_BUILD_HOST=archlinux From a0b80d147ea4dac112d3471f62d9ef890512f0fc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Dec 2024 04:24:03 +0100 Subject: [PATCH 078/236] Update Fedora kernels to v6.12.7 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 413c988b8d..83cec0a2ee 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.11.11-0" +PACKAGE_TAG = "kernel-6.12.7-0" ## ## The release number of the modified kernel package. From 795ede116ac1b322ce9f1ca0f30530838259b1da Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Dec 2024 04:36:32 +0100 Subject: [PATCH 079/236] pkg/arch: Use 'runuser' instead of 'su' for running 'makepkg' --- .github/scripts/package/arch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/package/arch.sh b/.github/scripts/package/arch.sh index 21ab798cb7..b5754b12c6 100644 --- a/.github/scripts/package/arch.sh +++ b/.github/scripts/package/arch.sh @@ -49,7 +49,7 @@ build-packages) export MAKEFLAGS="-j2" # Build - su nobody --pty -p -s /bin/bash -c 'makepkg -sf --skippgpcheck --noconfirm' + runuser -u nobody -- makepkg -sf --skippgpcheck --noconfirm # Prepare release mkdir release From add4c31a06d80393e34b6cae07f0f6c92fb2ec31 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Dec 2024 04:58:58 +0100 Subject: [PATCH 080/236] pkg/arch: Manually install build dependencies because sudo doesn't work any more --- .github/scripts/package/arch.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/scripts/package/arch.sh b/.github/scripts/package/arch.sh index b5754b12c6..972883fe8b 100644 --- a/.github/scripts/package/arch.sh +++ b/.github/scripts/package/arch.sh @@ -25,6 +25,14 @@ setup-builddeps) # Install tools for singing the kernel for secureboot pacman -S sbsigntools + + # Install actual build dependencies from PKGBUILD + pushd pkg/arch/kernel || exit 1 + + deps=$(bash -c 'source PKGBUILD && echo "${makedepends[@]}"') + pacman --noconfirm -S ${deps} + + popd || exit 1 ;; setup-secureboot) if [ -z "${SB_KEY:-}" ]; then @@ -40,7 +48,6 @@ build-packages) pushd pkg/arch/kernel || exit 1 # Fix permissions (can't makepkg as root) - echo "nobody ALL=(ALL) NOPASSWD: /usr/bin/pacman" >> /etc/sudoers chown -R nobody . # Package compression settings (Matches latest Arch) From 540aa7cd9a6bef775fc3488ba3d0b27b4a5ce1af Mon Sep 17 00:00:00 2001 From: tabletseeker <148603424+tabletseeker@users.noreply.github.com> Date: Sun, 16 Feb 2025 10:19:16 +0000 Subject: [PATCH 081/236] Updating patches for 6.14-rc2 Changes needed in: 0005-ipts.patch, 0006-ithc.patch, 0009-surface-typecover.patch All patches succeed with offset lines. --- patches/6.14-rc2/0001-secureboot.patch | 112 + patches/6.14-rc2/0002-surface3-oemb.patch | 101 + patches/6.14-rc2/0003-mwifiex.patch | 400 ++ patches/6.14-rc2/0004-ath10k.patch | 120 + patches/6.14-rc2/0005-ipts.patch | 3245 +++++++++++++++++ patches/6.14-rc2/0006-ithc.patch | 2773 ++++++++++++++ .../6.14-rc2/0007-surface-sam-over-hid.patch | 308 ++ patches/6.14-rc2/0008-surface-button.patch | 149 + patches/6.14-rc2/0009-surface-typecover.patch | 575 +++ patches/6.14-rc2/0010-surface-shutdown.patch | 97 + patches/6.14-rc2/0011-surface-gpe.patch | 51 + patches/6.14-rc2/0012-cameras.patch | 734 ++++ patches/6.14-rc2/0013-amd-gpio.patch | 109 + patches/6.14-rc2/0014-rtc.patch | 110 + 14 files changed, 8884 insertions(+) create mode 100644 patches/6.14-rc2/0001-secureboot.patch create mode 100644 patches/6.14-rc2/0002-surface3-oemb.patch create mode 100644 patches/6.14-rc2/0003-mwifiex.patch create mode 100644 patches/6.14-rc2/0004-ath10k.patch create mode 100644 patches/6.14-rc2/0005-ipts.patch create mode 100644 patches/6.14-rc2/0006-ithc.patch create mode 100644 patches/6.14-rc2/0007-surface-sam-over-hid.patch create mode 100644 patches/6.14-rc2/0008-surface-button.patch create mode 100644 patches/6.14-rc2/0009-surface-typecover.patch create mode 100644 patches/6.14-rc2/0010-surface-shutdown.patch create mode 100644 patches/6.14-rc2/0011-surface-gpe.patch create mode 100644 patches/6.14-rc2/0012-cameras.patch create mode 100644 patches/6.14-rc2/0013-amd-gpio.patch create mode 100644 patches/6.14-rc2/0014-rtc.patch diff --git a/patches/6.14-rc2/0001-secureboot.patch b/patches/6.14-rc2/0001-secureboot.patch new file mode 100644 index 0000000000..addb86e813 --- /dev/null +++ b/patches/6.14-rc2/0001-secureboot.patch @@ -0,0 +1,112 @@ +From bbcfb18eb05bd92e4501ca35bdfd558c849ddeda Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.47.1 + +From 9a796344897d077f1fc977ab026315c2cfcd3960 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index d401577b5a6a..5a812e0b740a 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3066,6 +3066,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index e35829d36039..6d54eb03b63d 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1426,6 +1427,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1484,3 +1491,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.47.1 + diff --git a/patches/6.14-rc2/0002-surface3-oemb.patch b/patches/6.14-rc2/0002-surface3-oemb.patch new file mode 100644 index 0000000000..ab40dd606c --- /dev/null +++ b/patches/6.14-rc2/0002-surface3-oemb.patch @@ -0,0 +1,101 @@ +From 2ce5cf2a597c9015c64ea9f386a396f97b8589c6 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-oemb +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index c15ed7a12784..1ec8edb5aafa 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.47.1 + diff --git a/patches/6.14-rc2/0003-mwifiex.patch b/patches/6.14-rc2/0003-mwifiex.patch new file mode 100644 index 0000000000..523a943588 --- /dev/null +++ b/patches/6.14-rc2/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From ed54461506b98c1bc8ae8dc5f7385de1f900ed0b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.47.1 + +From a93a869673e056cf2a2c46b9438edaca8f5e2645 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.47.1 + +From bcc616a02ed2a9e059d2e7a1dd5b5289412efcbb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 11755cb1eb16..e69c6c9957a2 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -432,6 +433,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -3837,6 +3839,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.47.1 + diff --git a/patches/6.14-rc2/0004-ath10k.patch b/patches/6.14-rc2/0004-ath10k.patch new file mode 100644 index 0000000000..e1e6253a8b --- /dev/null +++ b/patches/6.14-rc2/0004-ath10k.patch @@ -0,0 +1,120 @@ +From cc9a74a369def421de56b0581f6131c4cd15355d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index b3294287bce1..2936fdae823c 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.47.1 + diff --git a/patches/6.14-rc2/0005-ipts.patch b/patches/6.14-rc2/0005-ipts.patch new file mode 100644 index 0000000000..ea6999d915 --- /dev/null +++ b/patches/6.14-rc2/0005-ipts.patch @@ -0,0 +1,3245 @@ +From 3e89507b8f6c6d36e5bf587a74c65be5d9796ffd Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6589635f8ba3..a1df48a434e2 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.47.1 + +From 1d6df5a556693e735cc78a603c29112a76ee883b Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index cc23cfcdeb2d..c010aebe6cc1 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -40,6 +40,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -2046,6 +2053,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2344,6 +2354,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4651,6 +4664,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4686,6 +4711,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.47.1 + +From e4e616d49f7a021b83cd0114f0642090e88a054f Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index f8a56d631242..38eb29e4cc31 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1386,6 +1386,8 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + + source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 496dab54c73a..02588e5d01eb 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -171,5 +171,7 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.47.1 + diff --git a/patches/6.14-rc2/0006-ithc.patch b/patches/6.14-rc2/0006-ithc.patch new file mode 100644 index 0000000000..37c29e7924 --- /dev/null +++ b/patches/6.14-rc2/0006-ithc.patch @@ -0,0 +1,2773 @@ +From d07e07e448b9b1ac7102911263626b623f138a28 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 7a6d188e3bea..0179baee4596 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.47.1 + +From 280c63dff160b59d1cbac71a63dc7f16d335fec9 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 38eb29e4cc31..76ad7d9143c7 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1375,4 +1375,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 02588e5d01eb..1ea3d2e0d4e9 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,5 +173,6 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.47.1 + diff --git a/patches/6.14-rc2/0007-surface-sam-over-hid.patch b/patches/6.14-rc2/0007-surface-sam-over-hid.patch new file mode 100644 index 0000000000..a65acd8e4f --- /dev/null +++ b/patches/6.14-rc2/0007-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From 064893f3e33bd77cecece7ea4047b3a6e1147fe2 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index 14ae0cfc325e..6197c5252d2a 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.47.1 + +From f6714cb9a95aeec3379336df70e7cc8d9537f727 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.47.1 + diff --git a/patches/6.14-rc2/0008-surface-button.patch b/patches/6.14-rc2/0008-surface-button.patch new file mode 100644 index 0000000000..934e9156d2 --- /dev/null +++ b/patches/6.14-rc2/0008-surface-button.patch @@ -0,0 +1,149 @@ +From 9d06bf6cc92b13c9e4c4781484b82804c4150d80 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index 5c5d407fe965..4e1bfe90e730 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.47.1 + +From f870bb021693abb7ea617c323216c615151b62e1 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.47.1 + diff --git a/patches/6.14-rc2/0009-surface-typecover.patch b/patches/6.14-rc2/0009-surface-typecover.patch new file mode 100644 index 0000000000..7cc1b3eb95 --- /dev/null +++ b/patches/6.14-rc2/0009-surface-typecover.patch @@ -0,0 +1,575 @@ +From df8f9981df6f0a92100266397ded155314efc7e3 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 13171454f959..a83beefd25f3 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.47.1 + +From 3aa9fc5fd7faed0bd5948e80e6ef6173c32a83ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e936019d21fe..08fee06fb5fc 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -34,7 +34,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -168,6 +175,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -402,6 +412,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1751,6 +1771,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1774,6 +1857,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1812,8 +1898,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); +@@ -1822,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1873,6 +1963,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2299,6 +2390,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.47.1 + +From c88ebc0ed1f21ec7ad52aa4fb2c48226603d7596 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 08fee06fb5fc..f6664049f46d 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -414,6 +417,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1395,6 +1399,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1422,6 +1429,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1443,6 +1465,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1450,6 +1473,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1459,11 +1495,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1641,6 +1687,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1689,6 +1771,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1771,30 +1860,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1803,8 +1868,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1941,13 +2007,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1956,12 +2033,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.47.1 + diff --git a/patches/6.14-rc2/0010-surface-shutdown.patch b/patches/6.14-rc2/0010-surface-shutdown.patch new file mode 100644 index 0000000000..9194e85fe8 --- /dev/null +++ b/patches/6.14-rc2/0010-surface-shutdown.patch @@ -0,0 +1,97 @@ +From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 35270172c833..529779994ef6 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 8103bc24a54e..e8fa8d810925 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6301,3 +6301,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 4e77c4230c0a..a4b0e6ef6cfe 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -467,6 +467,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.47.1 + diff --git a/patches/6.14-rc2/0011-surface-gpe.patch b/patches/6.14-rc2/0011-surface-gpe.patch new file mode 100644 index 0000000000..cb83acb03c --- /dev/null +++ b/patches/6.14-rc2/0011-surface-gpe.patch @@ -0,0 +1,51 @@ +From 8120dc21068acfe547e9c6d1cced417e5931c7ad Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index 62fd4004db31..103fc4468262 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.47.1 + diff --git a/patches/6.14-rc2/0012-cameras.patch b/patches/6.14-rc2/0012-cameras.patch new file mode 100644 index 0000000000..64014fd030 --- /dev/null +++ b/patches/6.14-rc2/0012-cameras.patch @@ -0,0 +1,734 @@ +From 2cb3cbe91cb78a8747e6eee341c1d4e20c459d16 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 7ecc401fb97f..e35185de1902 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.47.1 + +From 29efdd823d22e0a6f7dead43d9c309602a1d2cbd Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index c010aebe6cc1..42b342184d56 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -45,6 +45,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -214,12 +221,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -2054,6 +2063,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2354,6 +2366,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4664,6 +4679,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4711,6 +4738,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.47.1 + +From 503ddf1a3c915d4b1108b44a280fd588fd11252c Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 1e107fd49f82..e3e1696e7f0e 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.47.1 + +From 46806f2df854794beb466026561dc6446ec77632 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 3de463c3d13b..0a012eeed30a 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ { } ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity ^= GPIO_ACTIVE_LOW; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) +-- +2.47.1 + +From af26f5acd84f8f7db95873690902562a159a94fb Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.47.1 + +From d0bcf0400f018b7d505f47bcf21ef7843f1372ca Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index f19c8adf2c61..923ed1b5ab8b 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.47.1 + +From 222586440493b857e7c5aa363f8741b7fff753be Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index e3e1696e7f0e..423dc555093f 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.47.1 + +From b0e450741669b478b74d8610fd9dbae817962077 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.47.1 + +From 7f546475ba781cf67aedd9817046b506873edab1 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index b784bb74a837..f8d8fcfacac2 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -941,6 +941,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 18afbb5a23ee..a1d16c0af82d 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.47.1 + +From adf794d65cca167d5bc66ef0c8a160e3fbeb3481 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.47.1 + diff --git a/patches/6.14-rc2/0013-amd-gpio.patch b/patches/6.14-rc2/0013-amd-gpio.patch new file mode 100644 index 0000000000..93c8956a23 --- /dev/null +++ b/patches/6.14-rc2/0013-amd-gpio.patch @@ -0,0 +1,109 @@ +From 28b8120e4f9b02ec49ccedd036557552a1aee5dc Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 4efecac49863..88377bb0d137 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.47.1 + +From 1b801d759aced457e5508cf931fa849400233b92 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 88377bb0d137..c58f26918b17 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.47.1 + diff --git a/patches/6.14-rc2/0014-rtc.patch b/patches/6.14-rc2/0014-rtc.patch new file mode 100644 index 0000000000..784921d06d --- /dev/null +++ b/patches/6.14-rc2/0014-rtc.patch @@ -0,0 +1,110 @@ +From 0a6b868f61d7564bc898ac30c84fbf3c34fb7368 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index b831cb8e53dc..78bd0f926505 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.47.1 + From 1e6b9f423e40f901e1b8228512d383184641f763 Mon Sep 17 00:00:00 2001 From: tabletseeker <148603424+tabletseeker@users.noreply.github.com> Date: Tue, 25 Feb 2025 08:28:11 +0000 Subject: [PATCH 082/236] Patches for 6.14-rc4 Changes in: 0005-ipts.patch , 0006-ithc.patch --- patches/6.14-rc4/0001-secureboot.patch | 112 + patches/6.14-rc4/0002-surface3-oemb.patch | 101 + patches/6.14-rc4/0003-mwifiex.patch | 400 ++ patches/6.14-rc4/0004-ath10k.patch | 120 + patches/6.14-rc4/0005-ipts.patch | 3250 +++++++++++++++++ patches/6.14-rc4/0006-ithc.patch | 2779 ++++++++++++++ .../6.14-rc4/0007-surface-sam-over-hid.patch | 308 ++ patches/6.14-rc4/0008-surface-button.patch | 149 + patches/6.14-rc4/0009-surface-typecover.patch | 575 +++ patches/6.14-rc4/0010-surface-shutdown.patch | 97 + patches/6.14-rc4/0011-surface-gpe.patch | 51 + patches/6.14-rc4/0012-cameras.patch | 734 ++++ patches/6.14-rc4/0013-amd-gpio.patch | 109 + patches/6.14-rc4/0014-rtc.patch | 110 + 14 files changed, 8895 insertions(+) create mode 100644 patches/6.14-rc4/0001-secureboot.patch create mode 100644 patches/6.14-rc4/0002-surface3-oemb.patch create mode 100644 patches/6.14-rc4/0003-mwifiex.patch create mode 100644 patches/6.14-rc4/0004-ath10k.patch create mode 100644 patches/6.14-rc4/0005-ipts.patch create mode 100644 patches/6.14-rc4/0006-ithc.patch create mode 100644 patches/6.14-rc4/0007-surface-sam-over-hid.patch create mode 100644 patches/6.14-rc4/0008-surface-button.patch create mode 100644 patches/6.14-rc4/0009-surface-typecover.patch create mode 100644 patches/6.14-rc4/0010-surface-shutdown.patch create mode 100644 patches/6.14-rc4/0011-surface-gpe.patch create mode 100644 patches/6.14-rc4/0012-cameras.patch create mode 100644 patches/6.14-rc4/0013-amd-gpio.patch create mode 100644 patches/6.14-rc4/0014-rtc.patch diff --git a/patches/6.14-rc4/0001-secureboot.patch b/patches/6.14-rc4/0001-secureboot.patch new file mode 100644 index 0000000000..addb86e813 --- /dev/null +++ b/patches/6.14-rc4/0001-secureboot.patch @@ -0,0 +1,112 @@ +From bbcfb18eb05bd92e4501ca35bdfd558c849ddeda Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.47.1 + +From 9a796344897d077f1fc977ab026315c2cfcd3960 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index d401577b5a6a..5a812e0b740a 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3066,6 +3066,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index e35829d36039..6d54eb03b63d 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1426,6 +1427,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1484,3 +1491,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.47.1 + diff --git a/patches/6.14-rc4/0002-surface3-oemb.patch b/patches/6.14-rc4/0002-surface3-oemb.patch new file mode 100644 index 0000000000..ab40dd606c --- /dev/null +++ b/patches/6.14-rc4/0002-surface3-oemb.patch @@ -0,0 +1,101 @@ +From 2ce5cf2a597c9015c64ea9f386a396f97b8589c6 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-oemb +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index c15ed7a12784..1ec8edb5aafa 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.47.1 + diff --git a/patches/6.14-rc4/0003-mwifiex.patch b/patches/6.14-rc4/0003-mwifiex.patch new file mode 100644 index 0000000000..523a943588 --- /dev/null +++ b/patches/6.14-rc4/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From ed54461506b98c1bc8ae8dc5f7385de1f900ed0b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.47.1 + +From a93a869673e056cf2a2c46b9438edaca8f5e2645 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.47.1 + +From bcc616a02ed2a9e059d2e7a1dd5b5289412efcbb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 11755cb1eb16..e69c6c9957a2 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -432,6 +433,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -3837,6 +3839,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.47.1 + diff --git a/patches/6.14-rc4/0004-ath10k.patch b/patches/6.14-rc4/0004-ath10k.patch new file mode 100644 index 0000000000..e1e6253a8b --- /dev/null +++ b/patches/6.14-rc4/0004-ath10k.patch @@ -0,0 +1,120 @@ +From cc9a74a369def421de56b0581f6131c4cd15355d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index b3294287bce1..2936fdae823c 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.47.1 + diff --git a/patches/6.14-rc4/0005-ipts.patch b/patches/6.14-rc4/0005-ipts.patch new file mode 100644 index 0000000000..dd23c2ea1b --- /dev/null +++ b/patches/6.14-rc4/0005-ipts.patch @@ -0,0 +1,3250 @@ +From 3e89507b8f6c6d36e5bf587a74c65be5d9796ffd Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6589635f8ba3..a1df48a434e2 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.47.1 + +From 1d6df5a556693e735cc78a603c29112a76ee883b Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index cc23cfcdeb2d..c010aebe6cc1 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -40,6 +40,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -2046,6 +2053,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2344,6 +2354,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4651,6 +4664,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4686,6 +4711,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.47.1 + +From e4e616d49f7a021b83cd0114f0642090e88a054f Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index f8a56d631242..38eb29e4cc31 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1386,11 +1386,13 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled + + source "drivers/hid/usbhid/Kconfig" + + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 496dab54c73a..02588e5d01eb 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -171,5 +171,7 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.47.1 + diff --git a/patches/6.14-rc4/0006-ithc.patch b/patches/6.14-rc4/0006-ithc.patch new file mode 100644 index 0000000000..5d30b51b11 --- /dev/null +++ b/patches/6.14-rc4/0006-ithc.patch @@ -0,0 +1,2779 @@ +From d07e07e448b9b1ac7102911263626b623f138a28 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 7a6d188e3bea..0179baee4596 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.47.1 + +From 280c63dff160b59d1cbac71a63dc7f16d335fec9 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 38eb29e4cc31..76ad7d9143c7 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1389,10 +1389,12 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled + + source "drivers/hid/usbhid/Kconfig" + + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 02588e5d01eb..1ea3d2e0d4e9 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,5 +173,6 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.47.1 + diff --git a/patches/6.14-rc4/0007-surface-sam-over-hid.patch b/patches/6.14-rc4/0007-surface-sam-over-hid.patch new file mode 100644 index 0000000000..a65acd8e4f --- /dev/null +++ b/patches/6.14-rc4/0007-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From 064893f3e33bd77cecece7ea4047b3a6e1147fe2 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index 14ae0cfc325e..6197c5252d2a 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.47.1 + +From f6714cb9a95aeec3379336df70e7cc8d9537f727 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.47.1 + diff --git a/patches/6.14-rc4/0008-surface-button.patch b/patches/6.14-rc4/0008-surface-button.patch new file mode 100644 index 0000000000..934e9156d2 --- /dev/null +++ b/patches/6.14-rc4/0008-surface-button.patch @@ -0,0 +1,149 @@ +From 9d06bf6cc92b13c9e4c4781484b82804c4150d80 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index 5c5d407fe965..4e1bfe90e730 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.47.1 + +From f870bb021693abb7ea617c323216c615151b62e1 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.47.1 + diff --git a/patches/6.14-rc4/0009-surface-typecover.patch b/patches/6.14-rc4/0009-surface-typecover.patch new file mode 100644 index 0000000000..7cc1b3eb95 --- /dev/null +++ b/patches/6.14-rc4/0009-surface-typecover.patch @@ -0,0 +1,575 @@ +From df8f9981df6f0a92100266397ded155314efc7e3 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 13171454f959..a83beefd25f3 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.47.1 + +From 3aa9fc5fd7faed0bd5948e80e6ef6173c32a83ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e936019d21fe..08fee06fb5fc 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -34,7 +34,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -168,6 +175,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -402,6 +412,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1751,6 +1771,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1774,6 +1857,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1812,8 +1898,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); +@@ -1822,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1873,6 +1963,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2299,6 +2390,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.47.1 + +From c88ebc0ed1f21ec7ad52aa4fb2c48226603d7596 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 08fee06fb5fc..f6664049f46d 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -414,6 +417,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1395,6 +1399,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1422,6 +1429,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1443,6 +1465,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1450,6 +1473,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1459,11 +1495,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1641,6 +1687,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1689,6 +1771,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1771,30 +1860,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1803,8 +1868,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1941,13 +2007,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1956,12 +2033,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.47.1 + diff --git a/patches/6.14-rc4/0010-surface-shutdown.patch b/patches/6.14-rc4/0010-surface-shutdown.patch new file mode 100644 index 0000000000..9194e85fe8 --- /dev/null +++ b/patches/6.14-rc4/0010-surface-shutdown.patch @@ -0,0 +1,97 @@ +From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 35270172c833..529779994ef6 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 8103bc24a54e..e8fa8d810925 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6301,3 +6301,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 4e77c4230c0a..a4b0e6ef6cfe 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -467,6 +467,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.47.1 + diff --git a/patches/6.14-rc4/0011-surface-gpe.patch b/patches/6.14-rc4/0011-surface-gpe.patch new file mode 100644 index 0000000000..cb83acb03c --- /dev/null +++ b/patches/6.14-rc4/0011-surface-gpe.patch @@ -0,0 +1,51 @@ +From 8120dc21068acfe547e9c6d1cced417e5931c7ad Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index 62fd4004db31..103fc4468262 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.47.1 + diff --git a/patches/6.14-rc4/0012-cameras.patch b/patches/6.14-rc4/0012-cameras.patch new file mode 100644 index 0000000000..64014fd030 --- /dev/null +++ b/patches/6.14-rc4/0012-cameras.patch @@ -0,0 +1,734 @@ +From 2cb3cbe91cb78a8747e6eee341c1d4e20c459d16 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 7ecc401fb97f..e35185de1902 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.47.1 + +From 29efdd823d22e0a6f7dead43d9c309602a1d2cbd Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index c010aebe6cc1..42b342184d56 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -45,6 +45,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -214,12 +221,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -2054,6 +2063,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2354,6 +2366,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4664,6 +4679,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4711,6 +4738,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.47.1 + +From 503ddf1a3c915d4b1108b44a280fd588fd11252c Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 1e107fd49f82..e3e1696e7f0e 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.47.1 + +From 46806f2df854794beb466026561dc6446ec77632 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 3de463c3d13b..0a012eeed30a 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ { } ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity ^= GPIO_ACTIVE_LOW; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) +-- +2.47.1 + +From af26f5acd84f8f7db95873690902562a159a94fb Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.47.1 + +From d0bcf0400f018b7d505f47bcf21ef7843f1372ca Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index f19c8adf2c61..923ed1b5ab8b 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.47.1 + +From 222586440493b857e7c5aa363f8741b7fff753be Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index e3e1696e7f0e..423dc555093f 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.47.1 + +From b0e450741669b478b74d8610fd9dbae817962077 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.47.1 + +From 7f546475ba781cf67aedd9817046b506873edab1 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index b784bb74a837..f8d8fcfacac2 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -941,6 +941,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 18afbb5a23ee..a1d16c0af82d 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.47.1 + +From adf794d65cca167d5bc66ef0c8a160e3fbeb3481 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.47.1 + diff --git a/patches/6.14-rc4/0013-amd-gpio.patch b/patches/6.14-rc4/0013-amd-gpio.patch new file mode 100644 index 0000000000..93c8956a23 --- /dev/null +++ b/patches/6.14-rc4/0013-amd-gpio.patch @@ -0,0 +1,109 @@ +From 28b8120e4f9b02ec49ccedd036557552a1aee5dc Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 4efecac49863..88377bb0d137 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.47.1 + +From 1b801d759aced457e5508cf931fa849400233b92 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 88377bb0d137..c58f26918b17 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.47.1 + diff --git a/patches/6.14-rc4/0014-rtc.patch b/patches/6.14-rc4/0014-rtc.patch new file mode 100644 index 0000000000..784921d06d --- /dev/null +++ b/patches/6.14-rc4/0014-rtc.patch @@ -0,0 +1,110 @@ +From 0a6b868f61d7564bc898ac30c84fbf3c34fb7368 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index b831cb8e53dc..78bd0f926505 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.47.1 + From ef25f89dca16c4cf97bb134dde107a32a5237826 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 01:27:06 +0100 Subject: [PATCH 083/236] Add patches for 6.13 Derived from latest 6.12 patches Links: - kernel: https://github.com/linux-surface/kernel/commit/4d3b956038eac47f59133a636a71b73b21fd1bb0 - tree-devel: https://github.com/linux-surface/kernel/commits/v6.13-surface-devel - tree-patches: https://github.com/linux-surface/kernel/commits/v6.13-surface --- configs/surface-6.13.config | 81 + patches/6.13/0001-secureboot.patch | 112 + patches/6.13/0002-surface3.patch | 234 ++ patches/6.13/0003-mwifiex.patch | 400 +++ patches/6.13/0004-ath10k.patch | 120 + patches/6.13/0005-ipts.patch | 3241 ++++++++++++++++++ patches/6.13/0006-ithc.patch | 41 + patches/6.13/0007-surface-sam.patch | 223 ++ patches/6.13/0008-ithc.patch | 2730 +++++++++++++++ patches/6.13/0009-surface-sam-over-hid.patch | 308 ++ patches/6.13/0010-surface-button.patch | 149 + patches/6.13/0011-surface-typecover.patch | 575 ++++ patches/6.13/0012-surface-shutdown.patch | 97 + patches/6.13/0013-surface-gpe.patch | 51 + patches/6.13/0014-cameras.patch | 734 ++++ patches/6.13/0015-amd-gpio.patch | 109 + patches/6.13/0016-rtc.patch | 110 + 17 files changed, 9315 insertions(+) create mode 100644 configs/surface-6.13.config create mode 100644 patches/6.13/0001-secureboot.patch create mode 100644 patches/6.13/0002-surface3.patch create mode 100644 patches/6.13/0003-mwifiex.patch create mode 100644 patches/6.13/0004-ath10k.patch create mode 100644 patches/6.13/0005-ipts.patch create mode 100644 patches/6.13/0006-ithc.patch create mode 100644 patches/6.13/0007-surface-sam.patch create mode 100644 patches/6.13/0008-ithc.patch create mode 100644 patches/6.13/0009-surface-sam-over-hid.patch create mode 100644 patches/6.13/0010-surface-button.patch create mode 100644 patches/6.13/0011-surface-typecover.patch create mode 100644 patches/6.13/0012-surface-shutdown.patch create mode 100644 patches/6.13/0013-surface-gpe.patch create mode 100644 patches/6.13/0014-cameras.patch create mode 100644 patches/6.13/0015-amd-gpio.patch create mode 100644 patches/6.13/0016-rtc.patch diff --git a/configs/surface-6.13.config b/configs/surface-6.13.config new file mode 100644 index 0000000000..05628a9957 --- /dev/null +++ b/configs/surface-6.13.config @@ -0,0 +1,81 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m diff --git a/patches/6.13/0001-secureboot.patch b/patches/6.13/0001-secureboot.patch new file mode 100644 index 0000000000..2001fa6210 --- /dev/null +++ b/patches/6.13/0001-secureboot.patch @@ -0,0 +1,112 @@ +From 4d009b53e8096425207fc6682b4678264ea70b8e Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.48.1 + +From f8c846bc0fc48b8399ea88427df65e12bf0e44db Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 3872bc6ec49d..e322b97879c2 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3074,6 +3074,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 10a01af63a80..e53e4a86e4cc 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1434,6 +1435,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1492,3 +1499,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.48.1 + diff --git a/patches/6.13/0002-surface3.patch b/patches/6.13/0002-surface3.patch new file mode 100644 index 0000000000..2a5ab67cef --- /dev/null +++ b/patches/6.13/0002-surface3.patch @@ -0,0 +1,234 @@ +From 1c36e25e29f59846a44c35a3bb204bfa0663860a Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3 +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index 6c8fb7a4dde4..22797a53f4d8 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.48.1 + +From b14f3b2d0baf0778bb4b1e69a692ae2b21987aec Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Fri, 6 Dec 2019 23:10:30 +0900 +Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by + default + +On Arch Linux kernel at least after 4.19, touch input is broken after suspend +(s2idle). + + kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + +On recent stable Arch Linux kernel (at least after 5.1), touch input will +crash after the first touch. + + kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue + +I found on an affected system (Arch Linux kernel, etc.), the touchscreen +driver uses DMA mode by default. Then, we found some kernels with different +kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel +chromeos-4.19 [2]) will use PIO mode by default and no such issues there. + +So, this commit disables DMA mode on the touchscreen driver side as a quick +workaround to avoid touch input crash. +We may need to properly set up DMA mode to use the touchscreen driver with +DMA mode. + +You can still switch DMA/PIO mode if you want: + + switch to DMA mode (maybe broken) + echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma + back to PIO mode + echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma + +Link to issue: https://github.com/jakeday/linux-surface/issues/596 + +References: +[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config +[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 + +Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. +This commit made the driver use PIO by default and no touch input crash. +Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default +even without this commit. After this commit, it still uses PIO and confirmed +no functional changes regarding touch input. + +More details: + We can confirm which mode the touchscreen driver uses; first, enable + debug output: + + echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + + Then, try to make a touch input and see dmesg log + + (On Arch Linux kernel, uses DMA) + kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA + kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 + c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + + (On the kernels I referenced above, uses PIO) + kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO + kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 + 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Note (2025-03-08): This patch was originally dropped due to the +comments in [3]. However, according to the commments in [4] it is still +required. + +[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a +[4]: https://github.com/linux-surface/linux-surface/issues/1184 + +Patchset: surface3 +--- + drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c +index 6074b7730e86..6aa3e1d6f160 100644 +--- a/drivers/input/touchscreen/surface3_spi.c ++++ b/drivers/input/touchscreen/surface3_spi.c +@@ -25,6 +25,12 @@ + #define SURFACE3_REPORT_TOUCH 0xd2 + #define SURFACE3_REPORT_PEN 0x16 + ++bool use_dma = false; ++module_param(use_dma, bool, 0644); ++MODULE_PARM_DESC(use_dma, ++ "Disable DMA mode if you encounter touch input crash. " ++ "(default: false, disabled to avoid crash)"); ++ + struct surface3_ts_data { + struct spi_device *spi; + struct gpio_desc *gpiod_rst[2]; +@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) + return 0; + } + ++static bool surface3_spi_can_dma(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) ++{ ++ return use_dma; ++} ++ + static int surface3_spi_probe(struct spi_device *spi) + { + struct surface3_ts_data *data; +@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) + if (error) + return error; + ++ /* ++ * Set up DMA ++ * ++ * TODO: Currently, touch input with DMA seems to be broken. ++ * On 4.19 LTS, touch input will crash after suspend. ++ * On recent stable kernel (at least after 5.1), touch input will crash after ++ * the first touch. No problem with PIO on those kernels. ++ * Maybe we need to configure DMA here. ++ * ++ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 ++ */ ++ spi->controller->can_dma = surface3_spi_can_dma; ++ + return 0; + } + +-- +2.48.1 + diff --git a/patches/6.13/0003-mwifiex.patch b/patches/6.13/0003-mwifiex.patch new file mode 100644 index 0000000000..f901b0ebd2 --- /dev/null +++ b/patches/6.13/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From 29f233ddc5afdf6f36d0049d7ee271445158dbdc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.48.1 + +From 98097d6f99d54495af0feee4345ed6d92d547e60 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.48.1 + +From 8d3ba13b4229f989721b335198b56d33ee508552 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 72e85673b709..110c983dfd53 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -440,6 +441,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -3869,6 +3871,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.48.1 + diff --git a/patches/6.13/0004-ath10k.patch b/patches/6.13/0004-ath10k.patch new file mode 100644 index 0000000000..ac7c63cbbe --- /dev/null +++ b/patches/6.13/0004-ath10k.patch @@ -0,0 +1,120 @@ +From fadbf4e719d243db53a4e644515dfd8f2b12198d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index b3294287bce1..2936fdae823c 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.48.1 + diff --git a/patches/6.13/0005-ipts.patch b/patches/6.13/0005-ipts.patch new file mode 100644 index 0000000000..24743210b6 --- /dev/null +++ b/patches/6.13/0005-ipts.patch @@ -0,0 +1,3241 @@ +From fc8b194519d2c8fd64a374ad5ca03b8d5cd0cf34 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6589635f8ba3..a1df48a434e2 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.48.1 + +From 75bd5dd5e9bb6724c24a8574ef33462be36574b5 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 9ab5371c3538..1839a831a89f 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -40,6 +40,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -1903,6 +1910,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2201,6 +2211,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4509,6 +4522,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4544,6 +4569,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.48.1 + +From c1562dcece75359bcc519d9a034f30fbe2c61f14 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 4d2a89d65b65..ce8e61de72c7 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1386,4 +1386,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + + source "drivers/hid/surface-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 24de45f3677d..c33ea76797a7 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -171,3 +171,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.48.1 + diff --git a/patches/6.13/0006-ithc.patch b/patches/6.13/0006-ithc.patch new file mode 100644 index 0000000000..300f37e1ab --- /dev/null +++ b/patches/6.13/0006-ithc.patch @@ -0,0 +1,41 @@ +From 761d58754af7780fa1fbc39764a8b944478aefa7 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 466c1412dd45..565686813588 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.48.1 + diff --git a/patches/6.13/0007-surface-sam.patch b/patches/6.13/0007-surface-sam.patch new file mode 100644 index 0000000000..70a8d46af8 --- /dev/null +++ b/patches/6.13/0007-surface-sam.patch @@ -0,0 +1,223 @@ +From 3029ed9429cdd6e7af835a2cbdb0e339d445a3ad Mon Sep 17 00:00:00 2001 +From: Lukas +Date: Sat, 8 Mar 2025 22:00:46 +0100 +Subject: [PATCH] platform/surface: aggregator_registry: Add support for + Surface Pro 11 + +Add Support for the Surface Pro 11. As the SAM clients are equivalent to +the Surface Pro 9, reuse its nodes. + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index d4f32ad66530..08b4ef382fab 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -371,7 +371,7 @@ static const struct software_node *ssam_node_group_sp8[] = { + NULL, + }; + +-/* Devices for Surface Pro 9 (Intel/x86) and 10 */ ++/* Devices for Surface Pro 9 (Intel/x86), 10 and 11 */ + static const struct software_node *ssam_node_group_sp9[] = { + &ssam_node_root, + &ssam_node_hub_kip, +@@ -430,6 +430,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Pro 10 */ + { "MSHW0510", (unsigned long)ssam_node_group_sp9 }, + ++ /* Surface Pro 11 */ ++ { "MSHW0583", (unsigned long)ssam_node_group_sp9 }, ++ + /* Surface Book 2 */ + { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, + +-- +2.48.1 + +From 6c57c2b436568f430841b64730f64e130d935b85 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 17 Jun 2022 02:14:00 +0200 +Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator + Module + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/rtc/Kconfig | 7 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 drivers/rtc/rtc-surface.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index a60bcc791a48..2de96e4c1ba6 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1383,6 +1383,13 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_SURFACE ++ tristate "Microsoft Surface Aggregator RTC" ++ depends on SURFACE_AGGREGATOR ++ depends on SURFACE_AGGREGATOR_BUS ++ help ++ TODO ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 489b4ab07068..061afa9db5b6 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -180,6 +180,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o + obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o + obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o + obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o ++obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o +diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c +new file mode 100644 +index 000000000000..f6c17c4e98d5 +--- /dev/null ++++ b/drivers/rtc/rtc-surface.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * AC driver for 7th-generation Microsoft Surface devices via Surface System ++ * Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2019-2021 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct surface_rtc { ++ struct ssam_device *sdev; ++ struct rtc_device *rtc; ++}; ++ ++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x10, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x0f, ++}); ++ ++static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) ++{ ++ __le32 time_le; ++ int status; ++ ++ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); ++ if (status) ++ return status; ++ ++ *time = le32_to_cpu(time_le); ++ return 0; ++} ++ ++static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) ++{ ++ __le32 time_le = cpu_to_le32(time); ++ ++ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); ++} ++ ++static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ int status; ++ u32 time; ++ ++ status = ssam_rtc_get_unix_time(srtc, &time); ++ if (status) ++ return status; ++ ++ rtc_time64_to_tm(time, tm); ++ return 0; ++} ++ ++static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ time64_t time = rtc_tm_to_time64(tm); ++ ++ return ssam_rtc_set_unix_time(srtc, (u32)time); ++} ++ ++static const struct rtc_class_ops surface_rtc_ops = { ++ .read_time = surface_rtc_read_time, ++ .set_time = surface_rtc_set_time, ++}; ++ ++static int surface_rtc_probe(struct ssam_device *sdev) ++{ ++ struct surface_rtc *srtc; ++ ++ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->sdev = sdev; ++ ++ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); ++ if (IS_ERR(srtc->rtc)) ++ return PTR_ERR(srtc->rtc); ++ ++ srtc->rtc->ops = &surface_rtc_ops; ++ srtc->rtc->range_max = U32_MAX; ++ ++ ssam_device_set_drvdata(sdev, srtc); ++ ++ return devm_rtc_register_device(srtc->rtc); ++} ++ ++static void surface_rtc_remove(struct ssam_device *sdev) ++{ ++ /* Device-managed allocations take care of everything... */ ++} ++ ++static const struct ssam_device_id surface_rtc_match[] = { ++ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, surface_rtc_match); ++ ++static struct ssam_device_driver surface_rtc_driver = { ++ .probe = surface_rtc_probe, ++ .remove = surface_rtc_remove, ++ .match_table = surface_rtc_match, ++ .driver = { ++ .name = "surface_rtc", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(surface_rtc_driver); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.48.1 + diff --git a/patches/6.13/0008-ithc.patch b/patches/6.13/0008-ithc.patch new file mode 100644 index 0000000000..045aba423d --- /dev/null +++ b/patches/6.13/0008-ithc.patch @@ -0,0 +1,2730 @@ +From f41db8abb594f79d041c4a8374ef3a4c771352de Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index ce8e61de72c7..db6665977a32 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1388,4 +1388,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index c33ea76797a7..6a89c1eb1b19 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,3 +173,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.48.1 + diff --git a/patches/6.13/0009-surface-sam-over-hid.patch b/patches/6.13/0009-surface-sam-over-hid.patch new file mode 100644 index 0000000000..9d935817fe --- /dev/null +++ b/patches/6.13/0009-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From 543a3df85dbf28bde744266be1e5b1c747ef14dc Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index d2499f302b50..77ce5ec3dd9e 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -661,6 +661,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -762,6 +783,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.48.1 + +From 591422fea78776d55694288325c4c3715b3c0f53 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.48.1 + diff --git a/patches/6.13/0010-surface-button.patch b/patches/6.13/0010-surface-button.patch new file mode 100644 index 0000000000..a7a94a98bf --- /dev/null +++ b/patches/6.13/0010-surface-button.patch @@ -0,0 +1,149 @@ +From faeac8d73d89cb1afc128ec9f3d8f2918073edb9 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index b8cad415c62c..43b5d56383e3 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.48.1 + +From 56058944284bd3dcf88182c4ae416e56121d6081 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.48.1 + diff --git a/patches/6.13/0011-surface-typecover.patch b/patches/6.13/0011-surface-typecover.patch new file mode 100644 index 0000000000..8c247b3b06 --- /dev/null +++ b/patches/6.13/0011-surface-typecover.patch @@ -0,0 +1,575 @@ +From 8ee5a38b312f141f0b859fa9198f04c06c946625 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 027479179f09..ee5a6bf5452d 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.48.1 + +From 9faca7b71f2573df9daa0d8452f5cde816a23487 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e50887a6d22c..4ce18f21a141 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -35,7 +35,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -73,12 +77,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -176,6 +183,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -220,6 +229,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -410,6 +420,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1759,6 +1779,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1782,6 +1865,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1820,8 +1906,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); +@@ -1830,8 +1918,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1881,6 +1971,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2304,6 +2395,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.48.1 + +From 05ac329ac19fb1bfce5f96d57552314c2269cf73 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 4ce18f21a141..f5e4d52bd2eb 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -85,6 +86,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -422,6 +425,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1403,6 +1407,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1430,6 +1437,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1451,6 +1473,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1458,6 +1481,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1467,11 +1503,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1646,6 +1692,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1694,6 +1776,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1779,30 +1868,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1811,8 +1876,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1949,13 +2015,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1964,12 +2041,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.48.1 + diff --git a/patches/6.13/0012-surface-shutdown.patch b/patches/6.13/0012-surface-shutdown.patch new file mode 100644 index 0000000000..f11d3ac18b --- /dev/null +++ b/patches/6.13/0012-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 9b0a957384c3dac5242656fca031988a9de2776f Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 35270172c833..529779994ef6 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 0a1f668999ce..c05c382c715d 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6314,3 +6314,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index f05903dd7695..d1e38fdaf8bb 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -476,6 +476,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.48.1 + diff --git a/patches/6.13/0013-surface-gpe.patch b/patches/6.13/0013-surface-gpe.patch new file mode 100644 index 0000000000..e10654a3ae --- /dev/null +++ b/patches/6.13/0013-surface-gpe.patch @@ -0,0 +1,51 @@ +From 6b2cd94b63214bf1222a6c76c9b9fac2e7ea657f Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index b359413903b1..b4496db79f39 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.48.1 + diff --git a/patches/6.13/0014-cameras.patch b/patches/6.13/0014-cameras.patch new file mode 100644 index 0000000000..10b0554232 --- /dev/null +++ b/patches/6.13/0014-cameras.patch @@ -0,0 +1,734 @@ +From fa2f30e8a9ffafc4b5d252710ec31ce0cc7aa305 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 74dcccdc6482..9b104f979abe 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.48.1 + +From 397c3bdd724c25652f126906b76b8bea75cdbdb4 Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 1839a831a89f..ebd7aa6b9038 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -45,6 +45,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -214,12 +221,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -1911,6 +1920,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2211,6 +2223,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4522,6 +4537,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4569,6 +4596,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.48.1 + +From abb050ef4eaa32a3215f9d9654bb6ecb5c67936c Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 81ac4c691963..f453c9043042 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.48.1 + +From b7c5caad1bf9174874378fa342c6a65c5da34bb9 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 09fff213b091..ce641eb45de6 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ { } ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity ^= GPIO_ACTIVE_LOW; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) +-- +2.48.1 + +From 7081b62ca502400be7d47b894a03106ee06c24be Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.48.1 + +From 69725089a7927bbd3795f0251127fc79301bbb4f Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index f19c8adf2c61..923ed1b5ab8b 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.48.1 + +From 0d33f9b4eb4a382c4d5351dced6937d2b713dd10 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index f453c9043042..b8ad6b413e8b 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.48.1 + +From d3cf5f12bc5cda4211bbe6d7f05b2d23dce5871f Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.48.1 + +From 0a70375485bb0c1ee51c3ec0ff20ddd3dfcdce38 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index b784bb74a837..f8d8fcfacac2 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -941,6 +941,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 18afbb5a23ee..a1d16c0af82d 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.48.1 + +From 71dea090c37acc5f7a0dfbcc8208cab62d1dcab8 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.48.1 + diff --git a/patches/6.13/0015-amd-gpio.patch b/patches/6.13/0015-amd-gpio.patch new file mode 100644 index 0000000000..4061f5e36a --- /dev/null +++ b/patches/6.13/0015-amd-gpio.patch @@ -0,0 +1,109 @@ +From 977d6a4eccbe4a54e06a510a7b553d9340193426 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 18485170d51b..66d1b9e8aa9d 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1172,6 +1173,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1228,6 +1240,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.48.1 + +From 0a3a25ae02896d38edd23b947a72b9fb587b159f Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 66d1b9e8aa9d..741e05190b41 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1175,12 +1175,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.48.1 + diff --git a/patches/6.13/0016-rtc.patch b/patches/6.13/0016-rtc.patch new file mode 100644 index 0000000000..2803a2da09 --- /dev/null +++ b/patches/6.13/0016-rtc.patch @@ -0,0 +1,110 @@ +From 4d3b956038eac47f59133a636a71b73b21fd1bb0 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 825c2a8acea4..74612088ac5f 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.48.1 + From 45606f9131ab06ed45554c3a088c2a68b104b096 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 01:38:05 +0100 Subject: [PATCH 084/236] pkg/debian: Add support for unprivileged_userns_clone --- ...sallow-unprivileged-CLONE_NEWUSER-by.patch | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch diff --git a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch new file mode 100644 index 0000000000..436ec5305e --- /dev/null +++ b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch @@ -0,0 +1,110 @@ +From 8da9938f2e7d28a5ae834bec723bc283dc62470f Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Fri, 31 May 2013 19:12:12 +0100 +Subject: [PATCH] add sysctl to disallow unprivileged CLONE_NEWUSER by default + +add sysctl to disallow unprivileged CLONE_NEWUSER by default + +This is a short-term patch. Unprivileged use of CLONE_NEWUSER +is certainly an intended feature of user namespaces. However +for at least saucy we want to make sure that, if any security +issues are found, we have a fail-safe. + +Signed-off-by: Serge Hallyn +[bwh: Remove unneeded binary sysctl bits] +[bwh: Keep this sysctl, but change the default to enabled] +--- + kernel/fork.c | 16 ++++++++++++++++ + kernel/sysctl.c | 13 +++++++++++++ + kernel/user_namespace.c | 3 +++ + 3 files changed, 32 insertions(+) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 9da032802e34..f3ad270eb96b 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -119,6 +119,12 @@ + + #include + ++#ifdef CONFIG_USER_NS ++extern int unprivileged_userns_clone; ++#else ++#define unprivileged_userns_clone 0 ++#endif ++ + /* + * Minimum number of threads to boot the kernel + */ +@@ -2169,6 +2175,10 @@ __latent_entropy struct task_struct *copy_process( + if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) + return ERR_PTR(-EINVAL); + ++ if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) ++ if (!capable(CAP_SYS_ADMIN)) ++ return ERR_PTR(-EPERM); ++ + /* + * Thread groups must share signals as well, and detached threads + * can only be started up within the thread group. +@@ -3322,6 +3332,12 @@ int ksys_unshare(unsigned long unshare_flags) + if (unshare_flags & CLONE_NEWNS) + unshare_flags |= CLONE_FS; + ++ if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { ++ err = -EPERM; ++ if (!capable(CAP_SYS_ADMIN)) ++ goto bad_unshare_out; ++ } ++ + err = check_unshare_flags(unshare_flags); + if (err) + goto bad_unshare_out; +diff --git a/kernel/sysctl.c b/kernel/sysctl.c +index 5c9202cb8f59..71102bca044e 100644 +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -135,6 +135,10 @@ static enum sysctl_writes_mode sysctl_writes_strict = SYSCTL_WRITES_STRICT; + int sysctl_legacy_va_layout; + #endif + ++#ifdef CONFIG_USER_NS ++extern int unprivileged_userns_clone; ++#endif ++ + #endif /* CONFIG_SYSCTL */ + + /* +@@ -1617,6 +1621,15 @@ static struct ctl_table kern_table[] = { + .mode = 0644, + .proc_handler = proc_dointvec, + }, ++#ifdef CONFIG_USER_NS ++ { ++ .procname = "unprivileged_userns_clone", ++ .data = &unprivileged_userns_clone, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++#endif + #ifdef CONFIG_PROC_SYSCTL + { + .procname = "tainted", +diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c +index aa0b2e47f2f2..222bb2b40b73 100644 +--- a/kernel/user_namespace.c ++++ b/kernel/user_namespace.c +@@ -22,6 +22,9 @@ + #include + #include + ++/* sysctl */ ++int unprivileged_userns_clone = 1; ++ + static struct kmem_cache *user_ns_cachep __ro_after_init; + static DEFINE_MUTEX(userns_state_mutex); + +-- +2.48.1 + From d64983512a8602da0250b7806440ad10e26d5c70 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 01:39:00 +0100 Subject: [PATCH 085/236] pkg/debian: Make sure .config is in the built package --- ...uild-Copy-config-to-target-directory.patch | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch diff --git a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch new file mode 100644 index 0000000000..516bbde169 --- /dev/null +++ b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch @@ -0,0 +1,25 @@ +From 6cf53165cd3876128648dadb76a718d02692e19d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Mar 2025 01:33:54 +0100 +Subject: [PATCH] kbuild: Copy config to target directory + +Partial revert of aaed5c7739be ("kbuild: slim down package for building +external modules"). Re-incldue the .config file. +--- + scripts/package/install-extmod-build | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build +index d3c5b104c063..d98da1f2bf02 100755 +--- a/scripts/package/install-extmod-build ++++ b/scripts/package/install-extmod-build +@@ -83,4 +83,6 @@ if [ "${CC}" != "${HOSTCC}" ]; then + rm -f "${destdir}/Kbuild" "${destdir}/scripts/Kbuild" + fi + ++# copy .config manually to be where it's expected to be ++cp "${KCONFIG_CONFIG}" "${destdir}/.config" + find "${destdir}" \( -name '.*.cmd' -o -name '*.o' \) -delete +-- +2.48.1 + From e6b1951c2a0e7651a62fc53ce95b9273bf3ed7cc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 01:48:16 +0100 Subject: [PATCH 086/236] fixup! Add patches for 6.13 --- patches/6.13/0006-ithc.patch | 2730 +++++++++++++++++ patches/6.13/0007-surface-sam.patch | 4 +- patches/6.13/0008-ithc.patch | 2730 ----------------- ....patch => 0008-surface-sam-over-hid.patch} | 4 +- ...button.patch => 0009-surface-button.patch} | 4 +- ...ver.patch => 0010-surface-typecover.patch} | 6 +- ...down.patch => 0011-surface-shutdown.patch} | 2 +- ...rface-gpe.patch => 0012-surface-gpe.patch} | 2 +- ...{0014-cameras.patch => 0013-cameras.patch} | 20 +- ...015-amd-gpio.patch => 0014-amd-gpio.patch} | 4 +- .../6.13/{0016-rtc.patch => 0015-rtc.patch} | 2 +- 11 files changed, 2754 insertions(+), 2754 deletions(-) delete mode 100644 patches/6.13/0008-ithc.patch rename patches/6.13/{0009-surface-sam-over-hid.patch => 0008-surface-sam-over-hid.patch} (98%) rename patches/6.13/{0010-surface-button.patch => 0009-surface-button.patch} (97%) rename patches/6.13/{0011-surface-typecover.patch => 0010-surface-typecover.patch} (98%) rename patches/6.13/{0012-surface-shutdown.patch => 0011-surface-shutdown.patch} (98%) rename patches/6.13/{0013-surface-gpe.patch => 0012-surface-gpe.patch} (95%) rename patches/6.13/{0014-cameras.patch => 0013-cameras.patch} (97%) rename patches/6.13/{0015-amd-gpio.patch => 0014-amd-gpio.patch} (96%) rename patches/6.13/{0016-rtc.patch => 0015-rtc.patch} (98%) diff --git a/patches/6.13/0006-ithc.patch b/patches/6.13/0006-ithc.patch index 300f37e1ab..b952ac6f0d 100644 --- a/patches/6.13/0006-ithc.patch +++ b/patches/6.13/0006-ithc.patch @@ -39,3 +39,2733 @@ index 466c1412dd45..565686813588 100644 -- 2.48.1 +From 4a1179f85e091a21417cc81b5e3813dbcc996107 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index ce8e61de72c7..db6665977a32 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1388,4 +1388,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index c33ea76797a7..6a89c1eb1b19 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,3 +173,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.48.1 + diff --git a/patches/6.13/0007-surface-sam.patch b/patches/6.13/0007-surface-sam.patch index 70a8d46af8..126878c15a 100644 --- a/patches/6.13/0007-surface-sam.patch +++ b/patches/6.13/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 3029ed9429cdd6e7af835a2cbdb0e339d445a3ad Mon Sep 17 00:00:00 2001 +From f380056e3a34dd28350a41869034943fe78d0041 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 8 Mar 2025 22:00:46 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -38,7 +38,7 @@ index d4f32ad66530..08b4ef382fab 100644 -- 2.48.1 -From 6c57c2b436568f430841b64730f64e130d935b85 Mon Sep 17 00:00:00 2001 +From 0fb14f0e1961e47fed10351be0793d44708ea3ad Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator diff --git a/patches/6.13/0008-ithc.patch b/patches/6.13/0008-ithc.patch deleted file mode 100644 index 045aba423d..0000000000 --- a/patches/6.13/0008-ithc.patch +++ /dev/null @@ -1,2730 +0,0 @@ -From f41db8abb594f79d041c4a8374ef3a4c771352de Mon Sep 17 00:00:00 2001 -From: quo -Date: Sun, 11 Dec 2022 12:10:54 +0100 -Subject: [PATCH] hid: Add support for Intel Touch Host Controller - -Based on quo/ithc-linux@34539af4726d. - -Signed-off-by: Maximilian Stoll -Patchset: ithc ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 1 + - drivers/hid/ithc/Kbuild | 6 + - drivers/hid/ithc/Kconfig | 12 + - drivers/hid/ithc/ithc-debug.c | 149 ++++++++ - drivers/hid/ithc/ithc-debug.h | 7 + - drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ - drivers/hid/ithc/ithc-dma.h | 47 +++ - drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ - drivers/hid/ithc/ithc-hid.h | 32 ++ - drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ - drivers/hid/ithc/ithc-legacy.h | 8 + - drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.h | 39 ++ - drivers/hid/ithc/ithc-regs.c | 154 ++++++++ - drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ - drivers/hid/ithc/ithc.h | 89 +++++ - 18 files changed, 2568 insertions(+) - create mode 100644 drivers/hid/ithc/Kbuild - create mode 100644 drivers/hid/ithc/Kconfig - create mode 100644 drivers/hid/ithc/ithc-debug.c - create mode 100644 drivers/hid/ithc/ithc-debug.h - create mode 100644 drivers/hid/ithc/ithc-dma.c - create mode 100644 drivers/hid/ithc/ithc-dma.h - create mode 100644 drivers/hid/ithc/ithc-hid.c - create mode 100644 drivers/hid/ithc/ithc-hid.h - create mode 100644 drivers/hid/ithc/ithc-legacy.c - create mode 100644 drivers/hid/ithc/ithc-legacy.h - create mode 100644 drivers/hid/ithc/ithc-main.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.h - create mode 100644 drivers/hid/ithc/ithc-regs.c - create mode 100644 drivers/hid/ithc/ithc-regs.h - create mode 100644 drivers/hid/ithc/ithc.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index ce8e61de72c7..db6665977a32 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1388,4 +1388,6 @@ source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/ipts/Kconfig" - -+source "drivers/hid/ithc/Kconfig" -+ - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index c33ea76797a7..6a89c1eb1b19 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -173,3 +173,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - - obj-$(CONFIG_HID_IPTS) += ipts/ -+obj-$(CONFIG_HID_ITHC) += ithc/ -diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild -new file mode 100644 -index 000000000000..4937ba131297 ---- /dev/null -+++ b/drivers/hid/ithc/Kbuild -@@ -0,0 +1,6 @@ -+obj-$(CONFIG_HID_ITHC) := ithc.o -+ -+ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o -+ -+ccflags-y := -std=gnu11 -Wno-declaration-after-statement -+ -diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig -new file mode 100644 -index 000000000000..ede713023609 ---- /dev/null -+++ b/drivers/hid/ithc/Kconfig -@@ -0,0 +1,12 @@ -+config HID_ITHC -+ tristate "Intel Touch Host Controller" -+ depends on PCI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Touch Host Controller (ITHC / IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ithc. -diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c -new file mode 100644 -index 000000000000..2d8c6afe9966 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.c -@@ -0,0 +1,149 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+void ithc_log_regs(struct ithc *ithc) -+{ -+ if (!ithc->prev_regs) -+ return; -+ u32 __iomem *cur = (__iomem void *)ithc->regs; -+ u32 *prev = (void *)ithc->prev_regs; -+ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { -+ u32 x = readl(cur + i); -+ if (x != prev[i]) { -+ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); -+ prev[i] = x; -+ } -+ } -+} -+ -+static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, -+ loff_t *offset) -+{ -+ // Debug commands consist of a single letter followed by a list of numbers (decimal or -+ // hexadecimal, space-separated). -+ struct ithc *ithc = file_inode(f)->i_private; -+ char cmd[256]; -+ if (!ithc || !ithc->pci) -+ return -ENODEV; -+ if (!len) -+ return -EINVAL; -+ if (len >= sizeof(cmd)) -+ return -EINVAL; -+ if (copy_from_user(cmd, buf, len)) -+ return -EFAULT; -+ cmd[len] = 0; -+ if (cmd[len-1] == '\n') -+ cmd[len-1] = 0; -+ pci_info(ithc->pci, "debug command: %s\n", cmd); -+ -+ // Parse the list of arguments into a u32 array. -+ u32 n = 0; -+ const char *s = cmd + 1; -+ u32 a[32]; -+ while (*s && *s != '\n') { -+ if (n >= ARRAY_SIZE(a)) -+ return -EINVAL; -+ if (*s++ != ' ') -+ return -EINVAL; -+ char *e; -+ a[n++] = simple_strtoul(s, &e, 0); -+ if (e == s) -+ return -EINVAL; -+ s = e; -+ } -+ ithc_log_regs(ithc); -+ -+ // Execute the command. -+ switch (cmd[0]) { -+ case 'x': // reset -+ ithc_reset(ithc); -+ break; -+ case 'w': // write register: offset mask value -+ if (n != 3 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", -+ a[0], a[2], a[1]); -+ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); -+ break; -+ case 'r': // read register: offset -+ if (n != 1 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], -+ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); -+ break; -+ case 's': // spi command: cmd offset len data... -+ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ // set touch cfg: s 6 12 4 XX -+ if (n < 3 || a[2] > (n - 3) * 4) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); -+ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) -+ for (u32 i = 0; i < (a[2] + 3) / 4; i++) -+ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); -+ break; -+ case 'd': // dma command: cmd len data... -+ // get report descriptor: d 7 8 0 0 -+ // enable multitouch: d 3 2 0x0105 -+ if (n < 1) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); -+ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; -+ if (ithc_dma_tx(ithc, &data)) -+ pci_err(ithc->pci, "dma tx failed\n"); -+ break; -+ default: -+ return -EINVAL; -+ } -+ ithc_log_regs(ithc); -+ return len; -+} -+ -+static struct dentry *dbg_dir; -+ -+void __init ithc_debug_init_module(void) -+{ -+ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); -+ if (IS_ERR(d)) -+ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); -+ else -+ dbg_dir = d; -+} -+ -+void __exit ithc_debug_exit_module(void) -+{ -+ debugfs_remove_recursive(dbg_dir); -+ dbg_dir = NULL; -+} -+ -+static const struct file_operations ithc_debugfops_cmd = { -+ .owner = THIS_MODULE, -+ .write = ithc_debugfs_cmd_write, -+}; -+ -+static void ithc_debugfs_devres_release(struct device *dev, void *res) -+{ -+ struct dentry **dbgm = res; -+ debugfs_remove_recursive(*dbgm); -+} -+ -+int ithc_debug_init_device(struct ithc *ithc) -+{ -+ if (!dbg_dir) -+ return -ENOENT; -+ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); -+ if (!dbgm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, dbgm); -+ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); -+ if (IS_ERR(dbg)) -+ return PTR_ERR(dbg); -+ *dbgm = dbg; -+ -+ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); -+ if (IS_ERR(cmd)) -+ return PTR_ERR(cmd); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h -new file mode 100644 -index 000000000000..38c53d916bdb ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.h -@@ -0,0 +1,7 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+void ithc_debug_init_module(void); -+void ithc_debug_exit_module(void); -+int ithc_debug_init_device(struct ithc *ithc); -+void ithc_log_regs(struct ithc *ithc); -+ -diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c -new file mode 100644 -index 000000000000..bf4eab33062b ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.c -@@ -0,0 +1,312 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. -+// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. -+// This allows each data buffer to consist of multiple non-contiguous blocks of memory. -+ -+static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, -+ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) -+{ -+ p->num_pages = num_pages; -+ p->dir = dir; -+ // We allocate enough space to have one PRD per data buffer page, however if the data -+ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so -+ // some will remain unused (which is fine). -+ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); -+ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); -+ if (!p->addr) -+ return -ENOMEM; -+ if (p->dma_addr & (PAGE_SIZE - 1)) -+ return -EFAULT; -+ return 0; -+} -+ -+// Devres managed sg_table wrapper. -+struct ithc_sg_table { -+ void *addr; -+ struct sg_table sgt; -+ enum dma_data_direction dir; -+}; -+static void ithc_dma_sgtable_free(struct sg_table *sgt) -+{ -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_sg(sgt, sg, i) { -+ struct page *p = sg_page(sg); -+ if (p) -+ __free_page(p); -+ } -+ sg_free_table(sgt); -+} -+static void ithc_dma_data_devres_release(struct device *dev, void *res) -+{ -+ struct ithc_sg_table *sgt = res; -+ if (sgt->addr) -+ vunmap(sgt->addr); -+ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); -+ ithc_dma_sgtable_free(&sgt->sgt); -+} -+ -+static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b) -+{ -+ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be -+ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). -+ // We could use dma_alloc_noncontiguous(), however this still always allocates a single -+ // DMA mapped segment, which is more restrictive than what we need. -+ // Instead we use an sg_table of individually allocated pages. -+ struct page *pages[16]; -+ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) -+ return -EINVAL; -+ b->active_idx = -1; -+ struct ithc_sg_table *sgt = devres_alloc( -+ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); -+ if (!sgt) -+ return -ENOMEM; -+ sgt->dir = prds->dir; -+ -+ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { -+ struct scatterlist *sg; -+ int i; -+ bool ok = true; -+ for_each_sgtable_sg(&sgt->sgt, sg, i) { -+ // NOTE: don't need __GFP_DMA for PCI DMA -+ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); -+ if (!p) { -+ ok = false; -+ break; -+ } -+ sg_set_page(sg, p, PAGE_SIZE, 0); -+ } -+ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { -+ devres_add(&ithc->pci->dev, sgt); -+ b->sgt = &sgt->sgt; -+ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); -+ if (!b->addr) -+ return -ENOMEM; -+ return 0; -+ } -+ ithc_dma_sgtable_free(&sgt->sgt); -+ } -+ devres_free(sgt); -+ return -ENOMEM; -+} -+ -+static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Give a buffer to the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ if (b->active_idx >= 0) { -+ pci_err(ithc->pci, "buffer already active\n"); -+ return -EINVAL; -+ } -+ b->active_idx = idx; -+ if (prds->dir == DMA_TO_DEVICE) { -+ // TX buffer: Caller should have already filled the data buffer, so just fill -+ // the PRD and flush. -+ // (TODO: Support multi-page TX buffers. So far no device seems to use or need -+ // these though.) -+ if (b->data_size > PAGE_SIZE) -+ return -EINVAL; -+ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; -+ prd->size = b->data_size | PRD_FLAG_END; -+ flush_kernel_vmap_range(b->addr, b->data_size); -+ } else if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Reset PRDs. -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ prd->addr = sg_dma_address(sg) >> 10; -+ prd->size = sg_dma_len(sg); -+ prd++; -+ } -+ prd[-1].size |= PRD_FLAG_END; -+ } -+ dma_wmb(); // for the prds -+ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Take a buffer from the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ // This is purely a sanity check. We don't strictly need the idx parameter for this -+ // function, because it should always be the same as active_idx, unless we have a bug. -+ if (b->active_idx != idx) { -+ pci_err(ithc->pci, "wrong buffer index\n"); -+ return -EINVAL; -+ } -+ b->active_idx = -1; -+ if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Calculate actual received data size from PRDs. -+ dma_rmb(); // for the prds -+ b->data_size = 0; -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ unsigned int size = prd->size; -+ b->data_size += size & PRD_SIZE_MASK; -+ if (size & PRD_FLAG_END) -+ break; -+ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { -+ pci_err(ithc->pci, "truncated prd\n"); -+ break; -+ } -+ prd++; -+ } -+ invalidate_kernel_vmap_range(b->addr, b->data_size); -+ } -+ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_init(&rx->mutex); -+ -+ // Allocate buffers. -+ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", -+ NUM_RX_BUF, ithc->max_rx_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); -+ -+ // Init registers. -+ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); -+ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); -+ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); -+ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); -+ u8 head = readb(&ithc->regs->dma_rx[channel].head); -+ if (head) { -+ pci_err(ithc->pci, "head is nonzero (%u)\n", head); -+ return -EIO; -+ } -+ -+ // Init buffers. -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); -+ -+ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); -+ return 0; -+} -+ -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) -+{ -+ bitsb_set(&ithc->regs->dma_rx[channel].control, -+ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, -+ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); -+} -+ -+int ithc_dma_tx_init(struct ithc *ithc) -+{ -+ struct ithc_dma_tx *tx = &ithc->dma_tx; -+ mutex_init(&tx->mutex); -+ -+ // Allocate buffers. -+ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", -+ ithc->max_tx_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); -+ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); -+ -+ // Init registers. -+ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); -+ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); -+ -+ // Init buffers. -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ return 0; -+} -+ -+static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) -+{ -+ // Process all filled RX buffers from the ringbuffer. -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ unsigned int n = rx->num_received; -+ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); -+ while (1) { -+ u8 tail = n % NUM_RX_BUF; -+ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); -+ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); -+ // ringbuffer is full if tail_wrap == head_wrap -+ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG -+ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) -+ return 0; -+ -+ // take the buffer that the device just filled -+ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); -+ rx->num_received = ++n; -+ -+ // process data -+ struct ithc_data d; -+ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) -+ (ithc, b->addr, b->data_size, &d) < 0) { -+ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", -+ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); -+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -+ b->addr, min(b->data_size, 0x400u), 0); -+ } else { -+ ithc_hid_process_data(ithc, &d); -+ } -+ -+ // give the buffer back to the device -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); -+ } -+} -+int ithc_dma_rx(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_lock(&rx->mutex); -+ int ret = ithc_dma_rx_unlocked(ithc, channel); -+ mutex_unlock(&rx->mutex); -+ return ret; -+} -+ -+static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) -+{ -+ // Send a single TX buffer to the THC. -+ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ -+ // Fill the TX buffer with header and data. -+ ssize_t sz; -+ if (data->type == ITHC_DATA_RAW) { -+ sz = min(data->size, ithc->max_tx_size); -+ memcpy(ithc->dma_tx.buf.addr, data->data, sz); -+ } else { -+ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) -+ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); -+ } -+ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ if (sz < 0) { -+ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", -+ data->type, data->size, (int)sz); -+ return -EINVAL; -+ } -+ -+ // Let the THC process the buffer. -+ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); -+ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); -+ return 0; -+} -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) -+{ -+ mutex_lock(&ithc->dma_tx.mutex); -+ int ret = ithc_dma_tx_unlocked(ithc, data); -+ mutex_unlock(&ithc->dma_tx.mutex); -+ return ret; -+} -+ -diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h -new file mode 100644 -index 000000000000..1749a5819b3e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define PRD_SIZE_MASK 0xffffff -+#define PRD_FLAG_END 0x1000000 -+#define PRD_FLAG_SUCCESS 0x2000000 -+#define PRD_FLAG_ERROR 0x4000000 -+ -+struct ithc_phys_region_desc { -+ u64 addr; // physical addr/1024 -+ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds -+ u32 unused; -+}; -+ -+struct ithc_dma_prd_buffer { -+ void *addr; -+ dma_addr_t dma_addr; -+ u32 size; -+ u32 num_pages; // per data buffer -+ enum dma_data_direction dir; -+}; -+ -+struct ithc_dma_data_buffer { -+ void *addr; -+ struct sg_table *sgt; -+ int active_idx; -+ u32 data_size; -+}; -+ -+struct ithc_dma_tx { -+ struct mutex mutex; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer buf; -+}; -+ -+struct ithc_dma_rx { -+ struct mutex mutex; -+ u32 num_received; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; -+}; -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel); -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); -+int ithc_dma_tx_init(struct ithc *ithc); -+int ithc_dma_rx(struct ithc *ithc, u8 channel); -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); -+ -diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c -new file mode 100644 -index 000000000000..065646ab499e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.c -@@ -0,0 +1,207 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+static int ithc_hid_start(struct hid_device *hdev) { return 0; } -+static void ithc_hid_stop(struct hid_device *hdev) { } -+static int ithc_hid_open(struct hid_device *hdev) { return 0; } -+static void ithc_hid_close(struct hid_device *hdev) { } -+ -+static int ithc_hid_parse(struct hid_device *hdev) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; -+ WRITE_ONCE(ithc->hid.parse_done, false); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); -+ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), -+ msecs_to_jiffies(200))) { -+ ithc_log_regs(ithc); -+ return 0; -+ } -+ if (retries > 5) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "failed to read report descriptor\n"); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -+ } -+} -+ -+static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -+ size_t len, unsigned char rtype, int reqtype) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ if (!buf || !len) -+ return -EINVAL; -+ -+ struct ithc_data d = { .size = len, .data = buf }; -+ buf[0] = reportnum; -+ -+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_OUTPUT_REPORT; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_SET_FEATURE; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -+ d.type = ITHC_DATA_GET_FEATURE; -+ d.data = &reportnum; -+ d.size = 1; -+ -+ // Prepare for response. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = buf; -+ ithc->hid.get_feature_size = len; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ -+ // Transmit 'get feature' request. -+ int r = CHECK(ithc_dma_tx, ithc, &d); -+ if (!r) { -+ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, -+ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); -+ if (!r) -+ r = -ETIMEDOUT; -+ else if (r < 0) -+ r = -EINTR; -+ else -+ r = 0; -+ } -+ -+ // If everything went ok, the buffer has been filled with the response data. -+ // Return the response size. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = NULL; -+ if (!r) -+ r = ithc->hid.get_feature_size; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ return r; -+ } -+ -+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -+ rtype, reqtype, reportnum); -+ return -EINVAL; -+} -+ -+// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to -+// cast away the const to avoid a compiler warning... -+#define NOCONST(x) ((void *)x) -+ -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) -+{ -+ WARN_ON(!ithc->hid.dev); -+ if (!ithc->hid.dev) -+ return; -+ -+ switch (d->type) { -+ -+ case ITHC_DATA_IGNORE: -+ return; -+ -+ case ITHC_DATA_ERROR: -+ CHECK(ithc_reset, ithc); -+ return; -+ -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ // Response to the report descriptor request sent by ithc_hid_parse(). -+ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); -+ WRITE_ONCE(ithc->hid.parse_done, true); -+ wake_up(&ithc->hid.wait_parse); -+ return; -+ -+ case ITHC_DATA_INPUT_REPORT: -+ { -+ // Standard HID input report. -+ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); -+ if (r < 0) { -+ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", -+ r, d->size, d->size ? *(u8 *)d->data : 0); -+ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, -+ d->data, min(d->size, 0x400u), 0); -+ } -+ return; -+ } -+ -+ case ITHC_DATA_GET_FEATURE: -+ { -+ // Response to a 'get feature' request sent by ithc_hid_raw_request(). -+ bool done = false; -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ if (ithc->hid.get_feature_buf) { -+ if (d->size < ithc->hid.get_feature_size) -+ ithc->hid.get_feature_size = d->size; -+ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); -+ ithc->hid.get_feature_buf = NULL; -+ done = true; -+ } -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ if (done) { -+ wake_up(&ithc->hid.wait_get_feature); -+ } else { -+ // Received data without a matching request, or the request already -+ // timed out. (XXX What's the correct thing to do here?) -+ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, -+ NOCONST(d->data), d->size, 1); -+ } -+ return; -+ } -+ -+ default: -+ pci_err(ithc->pci, "unhandled data type %i\n", d->type); -+ return; -+ } -+} -+ -+static struct hid_ll_driver ithc_ll_driver = { -+ .start = ithc_hid_start, -+ .stop = ithc_hid_stop, -+ .open = ithc_hid_open, -+ .close = ithc_hid_close, -+ .parse = ithc_hid_parse, -+ .raw_request = ithc_hid_raw_request, -+}; -+ -+static void ithc_hid_devres_release(struct device *dev, void *res) -+{ -+ struct hid_device **hidm = res; -+ if (*hidm) -+ hid_destroy_device(*hidm); -+} -+ -+int ithc_hid_init(struct ithc *ithc) -+{ -+ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -+ if (!hidm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, hidm); -+ struct hid_device *hid = hid_allocate_device(); -+ if (IS_ERR(hid)) -+ return PTR_ERR(hid); -+ *hidm = hid; -+ -+ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -+ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -+ hid->ll_driver = &ithc_ll_driver; -+ hid->bus = BUS_PCI; -+ hid->vendor = ithc->vendor_id; -+ hid->product = ithc->product_id; -+ hid->version = 0x100; -+ hid->dev.parent = &ithc->pci->dev; -+ hid->driver_data = ithc; -+ -+ ithc->hid.dev = hid; -+ -+ init_waitqueue_head(&ithc->hid.wait_parse); -+ init_waitqueue_head(&ithc->hid.wait_get_feature); -+ mutex_init(&ithc->hid.get_feature_mutex); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h -new file mode 100644 -index 000000000000..599eb912c8c8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+enum ithc_data_type { -+ ITHC_DATA_IGNORE, -+ ITHC_DATA_RAW, -+ ITHC_DATA_ERROR, -+ ITHC_DATA_REPORT_DESCRIPTOR, -+ ITHC_DATA_INPUT_REPORT, -+ ITHC_DATA_OUTPUT_REPORT, -+ ITHC_DATA_GET_FEATURE, -+ ITHC_DATA_SET_FEATURE, -+}; -+ -+struct ithc_data { -+ enum ithc_data_type type; -+ u32 size; -+ const void *data; -+}; -+ -+struct ithc_hid { -+ struct hid_device *dev; -+ bool parse_done; -+ wait_queue_head_t wait_parse; -+ wait_queue_head_t wait_get_feature; -+ struct mutex get_feature_mutex; -+ void *get_feature_buf; -+ size_t get_feature_size; -+}; -+ -+int ithc_hid_init(struct ithc *ithc); -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); -+ -diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c -new file mode 100644 -index 000000000000..8883987fb352 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.c -@@ -0,0 +1,254 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) -+#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) -+ -+#define DEVCFG_TOUCH_MASK 0x3f -+#define DEVCFG_TOUCH_ENABLE BIT(0) -+#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) -+#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) -+#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) -+#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) -+ -+#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" -+ -+#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) -+#define DEVCFG_SPI_CLKDIV_8 BIT(4) -+#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) -+#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) -+#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) -+#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) -+#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) -+#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat -+#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) -+#define DEVCFG_SPI_UNKNOWN_25 BIT(25) -+#define DEVCFG_SPI_UNKNOWN_26 BIT(26) -+#define DEVCFG_SPI_UNKNOWN_27 BIT(27) -+#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this -+#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? -+ -+struct ithc_device_config { // (Example values are from an SP7+.) -+ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) -+ u32 error; // 04 = 0x00000000 -+ u32 dma_buf_sizes; // 08 = 0x000a00ff -+ u32 touch_cfg; // 0c = 0x0000001c -+ u32 touch_state; // 10 = 0x0000001c -+ u32 device_id; // 14 = 0x43495424 = "$TIC" -+ u32 spi_config; // 18 = 0xfda00a2e -+ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. -+ u16 product_id; // 1e = 0x0c1a -+ u32 revision; // 20 = 0x00000001 -+ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) -+ u32 command; // 28 = 0x00000000 -+ u32 fw_mode; // 2c = 0x00000000 (for fw update?) -+ u32 _unknown_30; // 30 = 0x00000000 -+ u8 eds_minor_ver; // 34 = 0x5e -+ u8 eds_major_ver; // 35 = 0x03 -+ u8 interface_rev; // 36 = 0x04 -+ u8 eu_kernel_ver; // 37 = 0x04 -+ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) -+ u32 _unknown_3c; // 3c = 0x00000002 -+}; -+static_assert(sizeof(struct ithc_device_config) == 64); -+ -+#define RX_CODE_INPUT_REPORT 3 -+#define RX_CODE_FEATURE_REPORT 4 -+#define RX_CODE_REPORT_DESCRIPTOR 5 -+#define RX_CODE_RESET 7 -+ -+#define TX_CODE_SET_FEATURE 3 -+#define TX_CODE_GET_FEATURE 4 -+#define TX_CODE_OUTPUT_REPORT 5 -+#define TX_CODE_GET_REPORT_DESCRIPTOR 7 -+ -+static int ithc_set_device_enabled(struct ithc *ithc, bool enable) -+{ -+ u32 x = ithc->legacy_touch_cfg = -+ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | -+ DEVCFG_TOUCH_HID_REPORT_ENABLE | -+ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); -+ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -+ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); -+} -+ -+int ithc_legacy_init(struct ithc *ithc) -+{ -+ // Since we don't yet know which SPI config the device wants, use default speed and mode -+ // initially for reading config data. -+ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); -+ -+ // Setting the following bit seems to make reading the config more reliable. -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ // Setting this bit may be necessary on ADL devices. -+ switch (ithc->pci->device) { -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); -+ break; -+ } -+ -+ // Take the touch device out of reset. -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -+ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) -+ break; -+ if (retries > 5) { -+ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", -+ readl(&ithc->regs->irq_cause)); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ if (msleep_interruptible(1000)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ -+ // Read configuration data. -+ u32 spi_cfg; -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ struct ithc_device_config config = { 0 }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); -+ u32 *p = (void *)&config; -+ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { -+ spi_cfg = config.spi_config; -+ ithc->vendor_id = config.vendor_id; -+ ithc->product_id = config.product_id; -+ ithc->product_rev = config.revision; -+ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); -+ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); -+ ithc->legacy_touch_cfg = config.touch_cfg; -+ ithc->have_config = true; -+ break; -+ } -+ if (retries > 10) { -+ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -+ config.device_id); -+ return -EIO; -+ } -+ pci_warn(ithc->pci, "failed to read config, retrying\n"); -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ // Apply SPI config and enable touch device. -+ CHECK_RET(ithc_set_spi_config, ithc, -+ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, -+ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : -+ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : -+ SPI_MODE_SINGLE, -+ SPI_MODE_SINGLE); -+ CHECK_RET(ithc_set_device_enabled, ithc, true); -+ ithc_log_regs(ithc); -+ return 0; -+} -+ -+void ithc_legacy_exit(struct ithc *ithc) -+{ -+ CHECK(ithc_set_device_enabled, ithc, false); -+} -+ -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct { -+ u32 code; -+ u32 data_size; -+ u32 _unknown[14]; -+ } *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // Note: RX data is not padded, even though TX data must be padded. -+ if (len != sizeof(*hdr) + hdr->data_size) -+ return -EMSGSIZE; -+ -+ dest->data = hdr + 1; -+ dest->size = hdr->data_size; -+ -+ switch (hdr->code) { -+ case RX_CODE_RESET: -+ // The THC sends a reset request when we need to reinitialize the device. -+ // This usually only happens if we send an invalid command or put the device -+ // in a bad state. -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case RX_CODE_REPORT_DESCRIPTOR: -+ // The descriptor is preceded by 8 nul bytes. -+ if (hdr->data_size < 8) -+ return -ENODATA; -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = (char *)(hdr + 1) + 8; -+ dest->size = hdr->data_size - 8; -+ return 0; -+ case RX_CODE_INPUT_REPORT: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ return 0; -+ case RX_CODE_FEATURE_REPORT: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct { -+ u32 code; -+ u32 data_size; -+ } *hdr = dest; -+ -+ size_t src_size = src->size; -+ const void *src_data = src->data; -+ const u64 get_report_desc_data = 0; -+ u32 code; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ code = TX_CODE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ code = TX_CODE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ code = TX_CODE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ code = TX_CODE_GET_REPORT_DESCRIPTOR; -+ src_size = sizeof(get_report_desc_data); -+ src_data = &get_report_desc_data; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->code = code; -+ hdr->data_size = src_size; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h -new file mode 100644 -index 000000000000..28d692462072 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.h -@@ -0,0 +1,8 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+int ithc_legacy_init(struct ithc *ithc); -+void ithc_legacy_exit(struct ithc *ithc); -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -new file mode 100644 -index 000000000000..ac56c253674b ---- /dev/null -+++ b/drivers/hid/ithc/ithc-main.c -@@ -0,0 +1,431 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+MODULE_DESCRIPTION("Intel Touch Host Controller driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+ -+static const struct pci_device_id ithc_pci_tbl[] = { -+ { -+ .vendor = PCI_VENDOR_ID_INTEL, -+ .device = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subdevice = PCI_ANY_ID, -+ .class = PCI_CLASS_INPUT_PEN << 8, -+ .class_mask = ~0, -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); -+ -+// Module parameters -+ -+static bool ithc_use_polling = false; -+module_param_named(poll, ithc_use_polling, bool, 0); -+MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); -+ -+// Since all known devices seem to use only channel 1, by default we disable channel 0. -+static bool ithc_use_rx0 = false; -+module_param_named(rx0, ithc_use_rx0, bool, 0); -+MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); -+ -+static bool ithc_use_rx1 = true; -+module_param_named(rx1, ithc_use_rx1, bool, 0); -+MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); -+ -+static int ithc_active_ltr_us = -1; -+module_param_named(activeltr, ithc_active_ltr_us, int, 0); -+MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); -+ -+static int ithc_idle_ltr_us = -1; -+module_param_named(idleltr, ithc_idle_ltr_us, int, 0); -+MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); -+ -+static unsigned int ithc_idle_delay_ms = 1000; -+module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); -+MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); -+ -+static bool ithc_log_regs_enabled = false; -+module_param_named(logregs, ithc_log_regs_enabled, bool, 0); -+MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); -+ -+// Interrupts/polling -+ -+static void ithc_disable_interrupts(struct ithc *ithc) -+{ -+ writel(0, &ithc->regs->error_control); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); -+} -+ -+static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) -+{ -+ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, -+ &ithc->regs->dma_rx[channel].status); -+} -+ -+static void ithc_clear_interrupts(struct ithc *ithc) -+{ -+ writel(0xffffffff, &ithc->regs->error_flags); -+ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, -+ &ithc->regs->dma_tx.status); -+} -+ -+static void ithc_idle_timer_callback(struct timer_list *t) -+{ -+ struct ithc *ithc = container_of(t, struct ithc, idle_timer); -+ ithc_set_ltr_idle(ithc); -+} -+ -+static void ithc_process(struct ithc *ithc) -+{ -+ ithc_log_regs(ithc); -+ -+ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. -+ // It does not appear to automatically go back to idle, so we switch it back after a delay. -+ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); -+ -+ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ -+ // Read and clear error bits -+ u32 err = readl(&ithc->regs->error_flags); -+ if (err) { -+ writel(err, &ithc->regs->error_flags); -+ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "error flags: 0x%08x\n", err); -+ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); -+ } -+ -+ // Process DMA rx -+ if (ithc_use_rx0) { -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ if (rx0) -+ ithc_dma_rx(ithc, 0); -+ } -+ if (ithc_use_rx1) { -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ if (rx1) -+ ithc_dma_rx(ithc, 1); -+ } -+ -+ ithc_log_regs(ithc); -+} -+ -+static irqreturn_t ithc_interrupt_thread(int irq, void *arg) -+{ -+ struct ithc *ithc = arg; -+ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", -+ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), -+ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), -+ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), -+ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), -+ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); -+ ithc_process(ithc); -+ return IRQ_HANDLED; -+} -+ -+static int ithc_poll_thread(void *arg) -+{ -+ struct ithc *ithc = arg; -+ unsigned int sleep = 100; -+ while (!kthread_should_stop()) { -+ u32 n = ithc->dma_rx[1].num_received; -+ ithc_process(ithc); -+ // Decrease polling interval to 20ms if we received data, otherwise slowly -+ // increase it up to 200ms. -+ sleep = n != ithc->dma_rx[1].num_received ? 20 -+ : min(200u, sleep + (sleep >> 4) + 1); -+ msleep_interruptible(sleep); -+ } -+ return 0; -+} -+ -+// Device initialization and shutdown -+ -+static void ithc_disable(struct ithc *ithc) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); -+ ithc_disable_interrupts(ithc); -+ ithc_clear_interrupts(ithc); -+} -+ -+static int ithc_init_device(struct ithc *ithc) -+{ -+ // Read ACPI config for QuickSPI mode -+ struct ithc_acpi_config cfg = { 0 }; -+ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); -+ if (!cfg.has_config) -+ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); -+ else -+ ithc_print_acpi_config(ithc, &cfg); -+ ithc->use_quickspi = cfg.has_config; -+ -+ // Shut down device -+ ithc_log_regs(ithc); -+ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; -+ ithc_disable(ithc); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); -+ ithc_log_regs(ithc); -+ -+ // If the device was previously enabled, wait a bit to make sure it's fully shut down. -+ if (was_enabled) -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ -+ // Set Latency Tolerance Reporting config. The device will automatically -+ // apply these values depending on whether it is active or idle. -+ // If active value is too high, DMA buffer data can become truncated. -+ // By default, we set the active LTR value to 50us, and idle to 100ms. -+ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 -+ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 -+ : 50 * 1000; -+ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 -+ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 -+ : 100 * 1000 * 1000; -+ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); -+ -+ if (ithc->use_quickspi) -+ CHECK_RET(ithc_quickspi_init, ithc, &cfg); -+ else -+ CHECK_RET(ithc_legacy_init, ithc); -+ -+ return 0; -+} -+ -+int ithc_reset(struct ithc *ithc) -+{ -+ // FIXME This should probably do devres_release_group()+ithc_start(). -+ // But because this is called during DMA processing, that would have to be done -+ // asynchronously (schedule_work()?). And with extra locking? -+ pci_err(ithc->pci, "reset\n"); -+ CHECK(ithc_init_device, ithc); -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "reset completed\n"); -+ return 0; -+} -+ -+static void ithc_stop(void *res) -+{ -+ struct ithc *ithc = res; -+ pci_dbg(ithc->pci, "stopping\n"); -+ ithc_log_regs(ithc); -+ -+ if (ithc->poll_thread) -+ CHECK(kthread_stop, ithc->poll_thread); -+ if (ithc->irq >= 0) -+ disable_irq(ithc->irq); -+ if (ithc->use_quickspi) -+ ithc_quickspi_exit(ithc); -+ else -+ ithc_legacy_exit(ithc); -+ ithc_disable(ithc); -+ del_timer_sync(&ithc->idle_timer); -+ -+ // Clear DMA config. -+ for (unsigned int i = 0; i < 2; i++) { -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); -+ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); -+ writeb(0, &ithc->regs->dma_rx[i].num_bufs); -+ writeb(0, &ithc->regs->dma_rx[i].num_prds); -+ } -+ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); -+ writeb(0, &ithc->regs->dma_tx.num_prds); -+ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "stopped\n"); -+} -+ -+static void ithc_clear_drvdata(void *res) -+{ -+ struct pci_dev *pci = res; -+ pci_set_drvdata(pci, NULL); -+} -+ -+static int ithc_start(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "starting\n"); -+ if (pci_get_drvdata(pci)) { -+ pci_err(pci, "device already initialized\n"); -+ return -EINVAL; -+ } -+ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) -+ return -ENOMEM; -+ -+ // Allocate/init main driver struct. -+ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); -+ if (!ithc) -+ return -ENOMEM; -+ ithc->irq = -1; -+ ithc->pci = pci; -+ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); -+ pci_set_drvdata(pci, ithc); -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); -+ if (ithc_log_regs_enabled) -+ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); -+ -+ // PCI initialization. -+ CHECK_RET(pcim_enable_device, pci); -+ pci_set_master(pci); -+ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); -+ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); -+ CHECK_RET(pci_set_power_state, pci, PCI_D0); -+ ithc->regs = pcim_iomap_table(pci)[0]; -+ -+ // Allocate IRQ. -+ if (!ithc_use_polling) { -+ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); -+ ithc->irq = CHECK(pci_irq_vector, pci, 0); -+ if (ithc->irq < 0) -+ return ithc->irq; -+ } -+ -+ // Initialize THC and touch device. -+ CHECK_RET(ithc_init_device, ithc); -+ -+ // Initialize HID and DMA. -+ CHECK_RET(ithc_hid_init, ithc); -+ if (ithc_use_rx0) -+ CHECK_RET(ithc_dma_rx_init, ithc, 0); -+ if (ithc_use_rx1) -+ CHECK_RET(ithc_dma_rx_init, ithc, 1); -+ CHECK_RET(ithc_dma_tx_init, ithc); -+ -+ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); -+ -+ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are -+ // disabled BEFORE the buffers are freed. -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); -+ -+ // Start polling/IRQ. -+ if (ithc_use_polling) { -+ pci_info(pci, "using polling instead of irq\n"); -+ // Use a thread instead of simple timer because we want to be able to sleep. -+ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); -+ if (IS_ERR(ithc->poll_thread)) { -+ int err = PTR_ERR(ithc->poll_thread); -+ ithc->poll_thread = NULL; -+ return err; -+ } -+ } else { -+ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, -+ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); -+ } -+ -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ -+ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, -+ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. -+ CHECK_RET(hid_add_device, ithc->hid.dev); -+ -+ CHECK(ithc_debug_init_device, ithc); -+ -+ ithc_set_ltr_idle(ithc); -+ -+ pci_dbg(pci, "started\n"); -+ return 0; -+} -+ -+static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) -+{ -+ pci_dbg(pci, "device probe\n"); -+ return ithc_start(pci); -+} -+ -+static void ithc_remove(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "device remove\n"); -+ // all cleanup is handled by devres -+} -+ -+// For suspend/resume, we just deinitialize and reinitialize everything. -+// TODO It might be cleaner to keep the HID device around, however we would then have to signal -+// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set -+// feature' requests. Hidraw does not seem to have a facility to do that. -+static int ithc_suspend(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm suspend\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_resume(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm resume\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_freeze(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm freeze\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_thaw(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm thaw\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_restore(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm restore\n"); -+ return ithc_start(pci); -+} -+ -+static struct pci_driver ithc_driver = { -+ .name = DEVNAME, -+ .id_table = ithc_pci_tbl, -+ .probe = ithc_probe, -+ .remove = ithc_remove, -+ .driver.pm = &(const struct dev_pm_ops) { -+ .suspend = ithc_suspend, -+ .resume = ithc_resume, -+ .freeze = ithc_freeze, -+ .thaw = ithc_thaw, -+ .restore = ithc_restore, -+ }, -+ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, -+}; -+ -+static int __init ithc_init(void) -+{ -+ ithc_debug_init_module(); -+ return pci_register_driver(&ithc_driver); -+} -+ -+static void __exit ithc_exit(void) -+{ -+ pci_unregister_driver(&ithc_driver); -+ ithc_debug_exit_module(); -+} -+ -+module_init(ithc_init); -+module_exit(ithc_exit); -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c -new file mode 100644 -index 000000000000..e2d1690b8cf8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.c -@@ -0,0 +1,607 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+// Some public THC/QuickSPI documentation can be found in: -+// - Intel Firmware Support Package repo: https://github.com/intel/FSP -+// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 -+ -+#include "ithc.h" -+ -+static const guid_t guid_hidspi = -+ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); -+static const guid_t guid_thc_quickspi = -+ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); -+static const guid_t guid_thc_ltr = -+ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); -+ -+// TODO The HIDSPI spec says revision should be 3. Should we try both? -+#define DSM_REV 2 -+ -+struct hidspi_header { -+ u8 type; -+ u16 len; -+ u8 id; -+} __packed; -+static_assert(sizeof(struct hidspi_header) == 4); -+ -+#define HIDSPI_INPUT_TYPE_DATA 1 -+#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 -+#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 -+#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 -+#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 -+#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 -+#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 -+#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 -+#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 -+ -+#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 -+#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 -+#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 -+#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 -+#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 -+#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 -+#define HIDSPI_OUTPUT_TYPE_COMMAND 7 -+ -+struct hidspi_device_descriptor { -+ u16 wDeviceDescLength; -+ u16 bcdVersion; -+ u16 wReportDescLength; -+ u16 wMaxInputLength; -+ u16 wMaxOutputLength; -+ u16 wMaxFragmentLength; -+ u16 wVendorID; -+ u16 wProductID; -+ u16 wVersionID; -+ u16 wFlags; -+ u32 dwReserved; -+}; -+static_assert(sizeof(struct hidspi_device_descriptor) == 24); -+ -+static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_INTEGER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); -+ *dest = (u32)o->integer.value; -+ ACPI_FREE(o); -+ return 1; -+} -+ -+static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_BUFFER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ if (o->buffer.length != len) { -+ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", -+ guid, func, o->buffer.length, len); -+ ACPI_FREE(o); -+ return -1; -+ } -+ memcpy(dest, o->buffer.pointer, len); -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); -+ ACPI_FREE(o); -+ return 1; -+} -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) -+{ -+ int r; -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ -+ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); -+ if (!cfg->has_config) -+ return 0; -+ -+ // HIDSPI settings -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_header_address = r > 0; -+ if (r > 0 && cfg->input_report_header_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", -+ cfg->input_report_header_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_body_address = r > 0; -+ if (r > 0 && cfg->input_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", -+ cfg->input_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_output_report_body_address = r > 0; -+ if (r > 0 && cfg->output_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", -+ cfg->output_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_read_opcode = r > 0; -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_write_opcode = r > 0; -+ -+ u32 flags; -+ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); -+ if (r < 0) -+ return r; -+ cfg->has_read_mode = cfg->has_write_mode = r > 0; -+ if (r > 0) { -+ cfg->read_mode = (flags >> 14) & 3; -+ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; -+ } -+ -+ // Quick SPI settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); -+ if (r < 0) -+ return r; -+ cfg->has_spi_frequency = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); -+ if (r < 0) -+ return r; -+ cfg->has_limit_packet_size = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); -+ if (r < 0) -+ return r; -+ cfg->has_tx_delay = r > 0; -+ if (r > 0) -+ cfg->tx_delay &= 0xffff; -+ -+ // LTR settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_active_ltr = r > 0; -+ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { -+ if (cfg->active_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", -+ cfg->active_ltr); -+ cfg->active_ltr = 500; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_idle_ltr = r > 0; -+ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { -+ if (cfg->idle_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", -+ cfg->idle_ltr); -+ cfg->idle_ltr = 500; -+ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) -+ cfg->idle_ltr = cfg->active_ltr; -+ } -+ -+ return 0; -+} -+ -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ if (!cfg->has_config) { -+ pci_info(ithc->pci, "No ACPI config"); -+ return; -+ } -+ -+ char input_report_header_address[16] = "-"; -+ if (cfg->has_input_report_header_address) -+ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); -+ char input_report_body_address[16] = "-"; -+ if (cfg->has_input_report_body_address) -+ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); -+ char output_report_body_address[16] = "-"; -+ if (cfg->has_output_report_body_address) -+ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); -+ char read_opcode[16] = "-"; -+ if (cfg->has_read_opcode) -+ sprintf(read_opcode, "0x%02x", cfg->read_opcode); -+ char write_opcode[16] = "-"; -+ if (cfg->has_write_opcode) -+ sprintf(write_opcode, "0x%02x", cfg->write_opcode); -+ char read_mode[16] = "-"; -+ if (cfg->has_read_mode) -+ sprintf(read_mode, "%i", cfg->read_mode); -+ char write_mode[16] = "-"; -+ if (cfg->has_write_mode) -+ sprintf(write_mode, "%i", cfg->write_mode); -+ char spi_frequency[16] = "-"; -+ if (cfg->has_spi_frequency) -+ sprintf(spi_frequency, "%u", cfg->spi_frequency); -+ char limit_packet_size[16] = "-"; -+ if (cfg->has_limit_packet_size) -+ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); -+ char tx_delay[16] = "-"; -+ if (cfg->has_tx_delay) -+ sprintf(tx_delay, "%u", cfg->tx_delay); -+ char active_ltr[16] = "-"; -+ if (cfg->has_active_ltr) -+ sprintf(active_ltr, "%u", cfg->active_ltr); -+ char idle_ltr[16] = "-"; -+ if (cfg->has_idle_ltr) -+ sprintf(idle_ltr, "%u", cfg->idle_ltr); -+ -+ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", -+ input_report_header_address, input_report_body_address, output_report_body_address, -+ read_opcode, write_opcode, read_mode, write_mode, -+ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); -+} -+ -+static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) -+{ -+ writeb(opcode, &ithc->regs->opcode[i].header); -+ writeb(opcode, &ithc->regs->opcode[i].single); -+ writeb(opcode, &ithc->regs->opcode[i].dual); -+ writeb(opcode, &ithc->regs->opcode[i].quad); -+} -+ -+static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); -+ -+ // SPI frequency and mode -+ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { -+ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); -+ return -EINVAL; -+ } -+ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); -+ bool clkdiv8 = clkdiv > 7; -+ if (clkdiv8) -+ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); -+ if (!clkdiv) -+ clkdiv = 1; -+ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, -+ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, -+ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); -+ -+ // SPI addresses and opcodes -+ if (cfg->has_input_report_header_address) -+ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); -+ if (cfg->has_input_report_body_address) { -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); -+ } -+ if (cfg->has_output_report_body_address) -+ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); -+ -+ switch (ithc->pci->device) { -+ // LKF/TGL don't support QuickSPI. -+ // For ADL, opcode layout is RX/TX/unused. -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ if (cfg->has_read_opcode) { -+ set_opcode(ithc, 0, cfg->read_opcode); -+ } -+ if (cfg->has_write_opcode) { -+ set_opcode(ithc, 1, cfg->write_opcode); -+ } -+ break; -+ // For MTL, opcode layout was changed to RX/RX/TX. -+ // (RPL layout is unknown.) -+ default: -+ if (cfg->has_read_opcode) { -+ set_opcode(ithc, 0, cfg->read_opcode); -+ set_opcode(ithc, 1, cfg->read_opcode); -+ } -+ if (cfg->has_write_opcode) { -+ set_opcode(ithc, 2, cfg->write_opcode); -+ } -+ break; -+ } -+ -+ ithc_log_regs(ithc); -+ -+ // The rest... -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), -+ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); -+ -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), -+ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(2)); -+ -+ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), -+ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); -+ -+ bitsl_set(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); -+ -+ return 0; -+} -+ -+static int wait_for_report(struct ithc *ithc) -+{ -+ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, -+ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); -+ -+ u32 h = readl(&ithc->regs->input_header); -+ ithc_log_regs(ithc); -+ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE -+ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { -+ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); -+ return -ENODATA; -+ } -+ return INPUT_HEADER_REPORT_LENGTH(h) * 4; -+} -+ -+static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing HIDSPI\n"); -+ -+ // HIDSPI initialization sequence: -+ // "1. The host shall invoke the ACPI reset method to clear the device state." -+ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); -+ if (ACPI_FAILURE(s)) { -+ pci_err(ithc->pci, "ACPI reset failed\n"); -+ return -EIO; -+ } -+ -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ -+ // "2. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing a device reset response." -+ int size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(struct hidspi_header)) { -+ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "3. The host shall read the reset response from the device at the Input Report addresses -+ // specified in ACPI." -+ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; -+ struct { -+ struct hidspi_header header; -+ union { -+ struct hidspi_device_descriptor device_desc; -+ u32 data[16]; -+ }; -+ } resp = { 0 }; -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { -+ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); -+ return -ENOMSG; -+ } -+ -+ // "4. The host shall then write an Output Report to the device at the Output Report Address -+ // specified in ACPI, requesting the Device Descriptor from the device." -+ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; -+ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); -+ -+ // "5. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing the Device Descriptor." -+ size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { -+ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "6. The host shall read the Device Descriptor from the Input Report addresses specified -+ // in ACPI." -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ memset(&resp, 0, sizeof(resp)); -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { -+ pci_err(ithc->pci, "received type %i instead of device descriptor\n", -+ resp.header.type); -+ return -ENOMSG; -+ } -+ struct hidspi_device_descriptor *d = &resp.device_desc; -+ if (resp.header.len < sizeof(*d)) { -+ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", -+ resp.header.len); -+ return -EMSGSIZE; -+ } -+ if (d->wDeviceDescLength != sizeof(*d)) { -+ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", -+ d->wDeviceDescLength); -+ return -EMSGSIZE; -+ } -+ -+ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", -+ d->bcdVersion, d->wReportDescLength, -+ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, -+ d->wVendorID, d->wProductID, d->wVersionID, -+ d->wFlags, d->dwReserved); -+ -+ ithc->vendor_id = d->wVendorID; -+ ithc->product_id = d->wProductID; -+ ithc->product_rev = d->wVersionID; -+ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, -+ d->wReportDescLength + sizeof(struct hidspi_header)); -+ ithc->max_tx_size = d->wMaxOutputLength; -+ ithc->have_config = true; -+ -+ // "7. The device and host shall then enter their "Ready" states - where the device may -+ // begin sending Input Reports, and the device shall be prepared for Output Reports from -+ // the host." -+ -+ return 0; -+} -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); -+ ithc_log_regs(ithc); -+ -+ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, -+ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); -+ -+ // TODO Do we need to set any of the following bits here? -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); -+ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ ithc_log_regs(ithc); -+ -+ return 0; -+} -+ -+void ithc_quickspi_exit(struct ithc *ithc) -+{ -+ // TODO Should we send HIDSPI 'power off' command? -+ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; -+ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; -+ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() -+} -+ -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct hidspi_header *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // TODO Do we need to handle HIDSPI packet fragmentation? -+ if (len < sizeof(*hdr) + hdr->len) -+ return -EMSGSIZE; -+ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) -+ return -EMSGSIZE; -+ -+ switch (hdr->type) { -+ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: -+ // TODO "When the device detects an error condition, it may interrupt and make -+ // available to the host an Input Report containing an unsolicited Reset Response. -+ // After receiving an unsolicited Reset Response, the host shall initiate the -+ // request procedure from step (4) in the [HIDSPI initialization] process." -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = hdr + 1; -+ dest->size = hdr->len; -+ return 0; -+ case HIDSPI_INPUT_TYPE_DATA: -+ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: -+ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_IGNORE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct hidspi_header *hdr = dest; -+ -+ size_t src_size = src->size; -+ const u8 *src_data = src->data; -+ u8 type; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; -+ src_size = 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ u8 id = 0; -+ if (src_size) { -+ id = *src_data++; -+ src_size--; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->type = type; -+ hdr->len = (u16)src_size; -+ hdr->id = id; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h -new file mode 100644 -index 000000000000..74d882f6b2f0 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.h -@@ -0,0 +1,39 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+struct ithc_acpi_config { -+ bool has_config: 1; -+ bool has_input_report_header_address: 1; -+ bool has_input_report_body_address: 1; -+ bool has_output_report_body_address: 1; -+ bool has_read_opcode: 1; -+ bool has_write_opcode: 1; -+ bool has_read_mode: 1; -+ bool has_write_mode: 1; -+ bool has_spi_frequency: 1; -+ bool has_limit_packet_size: 1; -+ bool has_tx_delay: 1; -+ bool has_active_ltr: 1; -+ bool has_idle_ltr: 1; -+ u32 input_report_header_address; -+ u32 input_report_body_address; -+ u32 output_report_body_address; -+ u8 read_opcode; -+ u8 write_opcode; -+ u8 read_mode; -+ u8 write_mode; -+ u32 spi_frequency; -+ u32 limit_packet_size; -+ u32 tx_delay; // us/10 // TODO use? -+ u32 active_ltr; // ns/1024 -+ u32 idle_ltr; // ns/1024 -+}; -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+void ithc_quickspi_exit(struct ithc *ithc); -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c -new file mode 100644 -index 000000000000..c0f13506af20 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.c -@@ -0,0 +1,154 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writel((readl(reg) & ~mask) | (val & mask), reg); -+} -+ -+void bitsb(__iomem u8 *reg, u8 mask, u8 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writeb((readb(reg) & ~mask) | (val & mask), reg); -+} -+ -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) -+{ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ u32 x; -+ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) -+{ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ u8 x; -+ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) -+{ -+ unsigned int s = 0; -+ u64 v = *ns; -+ while (v > 0x3ff) { -+ s++; -+ v >>= 5; -+ } -+ if (s > 5) { -+ s = 5; -+ v = 0x3ff; -+ } -+ *val = v; -+ *scale = s; -+ *ns = v << (5 * s); -+} -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) -+{ -+ unsigned int active_val, active_scale, idle_val, idle_scale; -+ calc_ltr(&active_ltr_ns, &active_val, &active_scale); -+ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); -+ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", -+ active_ltr_ns, idle_ltr_ns); -+ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | -+ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | -+ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), -+ &ithc->regs->ltr_config); -+} -+ -+void ithc_set_ltr_idle(struct ithc *ithc) -+{ -+ u32 ltr = readl(&ithc->regs->ltr_config); -+ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { -+ case LTR_CONFIG_STATUS_IDLE: -+ break; -+ case LTR_CONFIG_STATUS_ACTIVE: -+ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); -+ break; -+ default: -+ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); -+ break; -+ } -+} -+ -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) -+{ -+ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) -+ return -EINVAL; -+ static const char * const modes[] = { "single", "dual", "quad" }; -+ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", -+ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), -+ modes[read_mode], modes[write_mode]); -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | -+ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | -+ SPI_CONFIG_CLKDIV_8, -+ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | -+ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | -+ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); -+ return 0; -+} -+ -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) -+{ -+ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); -+ if (size > sizeof(ithc->regs->spi_cmd.data)) -+ return -EINVAL; -+ -+ // Wait if the device is still busy. -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ // Clear result flags. -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ -+ // Init SPI command data. -+ writeb(command, &ithc->regs->spi_cmd.code); -+ writew(size, &ithc->regs->spi_cmd.size); -+ writel(offset, &ithc->regs->spi_cmd.offset); -+ u32 *p = data, n = (size + 3) / 4; -+ for (u32 i = 0; i < n; i++) -+ writel(p[i], &ithc->regs->spi_cmd.data[i]); -+ -+ // Start transmission. -+ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ -+ // Read response. -+ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) -+ return -EIO; -+ if (readw(&ithc->regs->spi_cmd.size) != size) -+ return -EMSGSIZE; -+ for (u32 i = 0; i < n; i++) -+ p[i] = readl(&ithc->regs->spi_cmd.data[i]); -+ -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h -new file mode 100644 -index 000000000000..4f541fe533fa ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.h -@@ -0,0 +1,211 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) -+#define LTR_CONFIG_TOGGLE BIT(1) -+#define LTR_CONFIG_ENABLE_IDLE BIT(2) -+#define LTR_CONFIG_APPLY BIT(3) -+#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) -+#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) -+#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) -+#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) -+#define LTR_CONFIG_STATUS_ACTIVE BIT(30) -+#define LTR_CONFIG_STATUS_IDLE BIT(31) -+ -+#define CONTROL_QUIESCE BIT(1) -+#define CONTROL_IS_QUIESCED BIT(2) -+#define CONTROL_NRESET BIT(3) -+#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) -+#define CONTROL_READY BIT(29) -+ -+#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) -+#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) -+#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) -+#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) -+#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) -+#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write -+#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) -+ -+#define SPI_CLK_FREQ_BASE 125000000 -+#define SPI_MODE_SINGLE 0 -+#define SPI_MODE_DUAL 1 -+#define SPI_MODE_QUAD 2 -+ -+#define ERROR_CONTROL_UNKNOWN_0 BIT(0) -+#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs -+#define ERROR_CONTROL_UNKNOWN_2 BIT(2) -+#define ERROR_CONTROL_UNKNOWN_3 BIT(3) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? -+#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs -+ -+#define ERROR_STATUS_DMA BIT(28) -+#define ERROR_STATUS_SPI BIT(30) -+ -+#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message -+#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) -+#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) -+#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) -+#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) -+#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) -+#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) -+ -+#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define SPI_CMD_CONTROL_IRQ BIT(1) -+ -+#define SPI_CMD_CODE_READ 4 -+#define SPI_CMD_CODE_WRITE 6 -+ -+#define SPI_CMD_STATUS_DONE BIT(0) -+#define SPI_CMD_STATUS_ERROR BIT(1) -+#define SPI_CMD_STATUS_BUSY BIT(3) -+ -+#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define DMA_TX_CONTROL_IRQ BIT(3) -+ -+#define DMA_TX_STATUS_DONE BIT(0) -+#define DMA_TX_STATUS_ERROR BIT(1) -+#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) -+#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? -+ -+#define INPUT_HEADER_VERSION(x) ((x) & 0xf) -+#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) -+#define INPUT_HEADER_SYNC(x) ((x) >> 24) -+#define INPUT_HEADER_VERSION_VALUE 3 -+#define INPUT_HEADER_SYNC_VALUE 0x5a -+ -+#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) -+#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) -+ -+#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) -+#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) -+#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) -+#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) -+#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) -+#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) -+#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) -+ -+#define DMA_RX_CONTROL_ENABLE BIT(0) -+#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only -+#define DMA_RX_CONTROL_IRQ_DATA BIT(5) -+ -+#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? -+#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? -+#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices -+ -+#define DMA_RX_WRAP_FLAG BIT(7) -+ -+#define DMA_RX_STATUS_ERROR BIT(3) -+#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) -+#define DMA_RX_STATUS_HAVE_DATA BIT(5) -+#define DMA_RX_STATUS_ENABLED BIT(8) -+ -+#define INIT_UNKNOWN_GUC_2 BIT(2) -+#define INIT_UNKNOWN_3 BIT(3) -+#define INIT_UNKNOWN_GUC_4 BIT(4) -+#define INIT_UNKNOWN_5 BIT(5) -+#define INIT_UNKNOWN_31 BIT(31) -+ -+// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. -+#define COUNTER_RESET BIT(31) -+ -+struct ithc_registers { -+ /* 0000 */ u32 _unknown_0000[5]; -+ /* 0014 */ u32 ltr_config; -+ /* 0018 */ u32 _unknown_0018[1018]; -+ /* 1000 */ u32 _unknown_1000; -+ /* 1004 */ u32 _unknown_1004; -+ /* 1008 */ u32 control_bits; -+ /* 100c */ u32 _unknown_100c; -+ /* 1010 */ u32 spi_config; -+ struct { -+ /* 1014/1018/101c */ u8 header; -+ /* 1015/1019/101d */ u8 quad; -+ /* 1016/101a/101e */ u8 dual; -+ /* 1017/101b/101f */ u8 single; -+ } opcode[3]; -+ /* 1020 */ u32 error_control; -+ /* 1024 */ u32 error_status; // write to clear -+ /* 1028 */ u32 error_flags; // write to clear -+ /* 102c */ u32 _unknown_102c[5]; -+ struct { -+ /* 1040 */ u8 control; -+ /* 1041 */ u8 code; -+ /* 1042 */ u16 size; -+ /* 1044 */ u32 status; // write to clear -+ /* 1048 */ u32 offset; -+ /* 104c */ u32 data[16]; -+ /* 108c */ u32 _unknown_108c; -+ } spi_cmd; -+ struct { -+ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1098 */ u8 control; -+ /* 1099 */ u8 _unknown_1099; -+ /* 109a */ u8 _unknown_109a; -+ /* 109b */ u8 num_prds; -+ /* 109c */ u32 status; // write to clear -+ /* 10a0 */ u32 _unknown_10a0[5]; -+ /* 10b4 */ u32 spi_addr; -+ } dma_tx; -+ /* 10b8 */ u32 spi_header_addr; -+ union { -+ /* 10bc */ u32 irq_cause; // in legacy THC mode -+ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) -+ }; -+ /* 10c0 */ u32 _unknown_10c0[8]; -+ /* 10e0 */ u32 _unknown_10e0_counters[3]; -+ /* 10ec */ u32 quickspi_config1; -+ /* 10f0 */ u32 quickspi_config2; -+ /* 10f4 */ u32 _unknown_10f4[3]; -+ struct { -+ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1108/1208 */ u8 num_bufs; -+ /* 1109/1209 */ u8 num_prds; -+ /* 110a/120a */ u16 _unknown_110a; -+ /* 110c/120c */ u8 control; -+ /* 110d/120d */ u8 head; -+ /* 110e/120e */ u8 tail; -+ /* 110f/120f */ u8 control2; -+ /* 1110/1210 */ u32 status; // write to clear -+ /* 1114/1214 */ u32 _unknown_1114; -+ /* 1118/1218 */ u64 _unknown_1118_guc_addr; -+ /* 1120/1220 */ u32 _unknown_1120_guc; -+ /* 1124/1224 */ u32 _unknown_1124_guc; -+ /* 1128/1228 */ u32 init_unknown; -+ /* 112c/122c */ u32 _unknown_112c; -+ /* 1130/1230 */ u64 _unknown_1130_guc_addr; -+ /* 1138/1238 */ u32 _unknown_1138_guc; -+ /* 113c/123c */ u32 _unknown_113c; -+ /* 1140/1240 */ u32 _unknown_1140_guc; -+ /* 1144/1244 */ u32 _unknown_1144[11]; -+ /* 1170/1270 */ u32 spi_addr; -+ /* 1174/1274 */ u32 _unknown_1174[11]; -+ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; -+ /* 11b8/12b8 */ u32 _unknown_11b8[18]; -+ } dma_rx[2]; -+}; -+static_assert(sizeof(struct ithc_registers) == 0x1300); -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val); -+void bitsb(__iomem u8 *reg, u8 mask, u8 val); -+#define bitsl_set(reg, x) bitsl(reg, x, x) -+#define bitsb_set(reg, x) bitsb(reg, x, x) -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); -+void ithc_set_ltr_idle(struct ithc *ithc); -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); -+ -diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h -new file mode 100644 -index 000000000000..aec320d4e945 ---- /dev/null -+++ b/drivers/hid/ithc/ithc.h -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEVNAME "ithc" -+#define DEVFULLNAME "Intel Touch Host Controller" -+ -+#undef pr_fmt -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) -+#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) -+ -+#define NUM_RX_BUF 16 -+ -+// PCI device IDs: -+// Lakefield -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 -+// Tiger Lake -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 -+// Alder Lake -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 -+// Raptor Lake -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 -+// Meteor Lake -+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b -+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b -+ -+struct ithc; -+ -+#include "ithc-regs.h" -+#include "ithc-hid.h" -+#include "ithc-dma.h" -+#include "ithc-legacy.h" -+#include "ithc-quickspi.h" -+#include "ithc-debug.h" -+ -+struct ithc { -+ char phys[32]; -+ struct pci_dev *pci; -+ int irq; -+ struct task_struct *poll_thread; -+ struct timer_list idle_timer; -+ -+ struct ithc_registers __iomem *regs; -+ struct ithc_registers *prev_regs; // for debugging -+ struct ithc_dma_rx dma_rx[2]; -+ struct ithc_dma_tx dma_tx; -+ struct ithc_hid hid; -+ -+ bool use_quickspi; -+ bool have_config; -+ u16 vendor_id; -+ u16 product_id; -+ u32 product_rev; -+ u32 max_rx_size; -+ u32 max_tx_size; -+ u32 legacy_touch_cfg; -+}; -+ -+int ithc_reset(struct ithc *ithc); -+ --- -2.48.1 - diff --git a/patches/6.13/0009-surface-sam-over-hid.patch b/patches/6.13/0008-surface-sam-over-hid.patch similarity index 98% rename from patches/6.13/0009-surface-sam-over-hid.patch rename to patches/6.13/0008-surface-sam-over-hid.patch index 9d935817fe..0b93b98564 100644 --- a/patches/6.13/0009-surface-sam-over-hid.patch +++ b/patches/6.13/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 543a3df85dbf28bde744266be1e5b1c747ef14dc Mon Sep 17 00:00:00 2001 +From 28db0098e37b9ac1e261afd935c0e2c5e0ae3675 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index d2499f302b50..77ce5ec3dd9e 100644 -- 2.48.1 -From 591422fea78776d55694288325c4c3715b3c0f53 Mon Sep 17 00:00:00 2001 +From d7f160e91330f15f3ce5806dd2eeda08b67683e6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.13/0010-surface-button.patch b/patches/6.13/0009-surface-button.patch similarity index 97% rename from patches/6.13/0010-surface-button.patch rename to patches/6.13/0009-surface-button.patch index a7a94a98bf..738b8732b8 100644 --- a/patches/6.13/0010-surface-button.patch +++ b/patches/6.13/0009-surface-button.patch @@ -1,4 +1,4 @@ -From faeac8d73d89cb1afc128ec9f3d8f2918073edb9 Mon Sep 17 00:00:00 2001 +From cee06c726d818a4194f543f2fc99f69ed0a4a1ae Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.48.1 -From 56058944284bd3dcf88182c4ae416e56121d6081 Mon Sep 17 00:00:00 2001 +From 2b8ce3b47ac424db0c4ac408c8122ccc494aa6ae Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.13/0011-surface-typecover.patch b/patches/6.13/0010-surface-typecover.patch similarity index 98% rename from patches/6.13/0011-surface-typecover.patch rename to patches/6.13/0010-surface-typecover.patch index 8c247b3b06..b20bbc99c4 100644 --- a/patches/6.13/0011-surface-typecover.patch +++ b/patches/6.13/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 8ee5a38b312f141f0b859fa9198f04c06c946625 Mon Sep 17 00:00:00 2001 +From db94df7d6a30c9c4125013bd195ec41d4b04a379 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 027479179f09..ee5a6bf5452d 100644 -- 2.48.1 -From 9faca7b71f2573df9daa0d8452f5cde816a23487 Mon Sep 17 00:00:00 2001 +From d9c734fac1446ce245a98a5f592060cc20edb158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index e50887a6d22c..4ce18f21a141 100644 -- 2.48.1 -From 05ac329ac19fb1bfce5f96d57552314c2269cf73 Mon Sep 17 00:00:00 2001 +From 3e36c4a010af0175b6537a3e9b5f413e95105583 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.13/0012-surface-shutdown.patch b/patches/6.13/0011-surface-shutdown.patch similarity index 98% rename from patches/6.13/0012-surface-shutdown.patch rename to patches/6.13/0011-surface-shutdown.patch index f11d3ac18b..75db042d2f 100644 --- a/patches/6.13/0012-surface-shutdown.patch +++ b/patches/6.13/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 9b0a957384c3dac5242656fca031988a9de2776f Mon Sep 17 00:00:00 2001 +From 4f1f9492b46f9eee2ce9f844e03722acefaf5089 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.13/0013-surface-gpe.patch b/patches/6.13/0012-surface-gpe.patch similarity index 95% rename from patches/6.13/0013-surface-gpe.patch rename to patches/6.13/0012-surface-gpe.patch index e10654a3ae..0bec2f30c3 100644 --- a/patches/6.13/0013-surface-gpe.patch +++ b/patches/6.13/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 6b2cd94b63214bf1222a6c76c9b9fac2e7ea657f Mon Sep 17 00:00:00 2001 +From 424492cfdcccf128c28222d3bb3ba3f2ee05e3bd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.13/0014-cameras.patch b/patches/6.13/0013-cameras.patch similarity index 97% rename from patches/6.13/0014-cameras.patch rename to patches/6.13/0013-cameras.patch index 10b0554232..2759b52546 100644 --- a/patches/6.13/0014-cameras.patch +++ b/patches/6.13/0013-cameras.patch @@ -1,4 +1,4 @@ -From fa2f30e8a9ffafc4b5d252710ec31ce0cc7aa305 Mon Sep 17 00:00:00 2001 +From eff5ad8dccd6f5a16bccaf8dff294af5d429e8ad Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index 74dcccdc6482..9b104f979abe 100644 -- 2.48.1 -From 397c3bdd724c25652f126906b76b8bea75cdbdb4 Mon Sep 17 00:00:00 2001 +From fac80ec3139641ff4c494e7cd09d1648c7d8b2be Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 1839a831a89f..ebd7aa6b9038 100644 -- 2.48.1 -From abb050ef4eaa32a3215f9d9654bb6ecb5c67936c Mon Sep 17 00:00:00 2001 +From f451c52ee26ece5d7019766e438a981ef6fe112c Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 81ac4c691963..f453c9043042 100644 -- 2.48.1 -From b7c5caad1bf9174874378fa342c6a65c5da34bb9 Mon Sep 17 00:00:00 2001 +From 04c30b68d29d35c3f1648919d191249b17f0b487 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -277,7 +277,7 @@ index 09fff213b091..ce641eb45de6 100644 -- 2.48.1 -From 7081b62ca502400be7d47b894a03106ee06c24be Mon Sep 17 00:00:00 2001 +From 45854373b2c865431add3e249e42090cb2412057 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -316,7 +316,7 @@ index 30f61e04ecaf..9c1292ca8552 100644 -- 2.48.1 -From 69725089a7927bbd3795f0251127fc79301bbb4f Mon Sep 17 00:00:00 2001 +From 7ae7dc83e5f08fafe78b6737b3d1ac6aa1c932a1 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -367,7 +367,7 @@ index f19c8adf2c61..923ed1b5ab8b 100644 -- 2.48.1 -From 0d33f9b4eb4a382c4d5351dced6937d2b713dd10 Mon Sep 17 00:00:00 2001 +From d20654efdf6f940456501405e90e3ed096a64258 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -408,7 +408,7 @@ index f453c9043042..b8ad6b413e8b 100644 -- 2.48.1 -From d3cf5f12bc5cda4211bbe6d7f05b2d23dce5871f Mon Sep 17 00:00:00 2001 +From b46660642fed87df97974c1eb864bff34cb5f67c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -449,7 +449,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.48.1 -From 0a70375485bb0c1ee51c3ec0ff20ddd3dfcdce38 Mon Sep 17 00:00:00 2001 +From 6771f76a6415179f12d68c24f599405f2ac939f1 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -700,7 +700,7 @@ index 000000000000..35aeb5db89c8 -- 2.48.1 -From 71dea090c37acc5f7a0dfbcc8208cab62d1dcab8 Mon Sep 17 00:00:00 2001 +From b00c21087ed9b70395b20328c11f2b43f4e07a99 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.13/0015-amd-gpio.patch b/patches/6.13/0014-amd-gpio.patch similarity index 96% rename from patches/6.13/0015-amd-gpio.patch rename to patches/6.13/0014-amd-gpio.patch index 4061f5e36a..c6963a26c9 100644 --- a/patches/6.13/0015-amd-gpio.patch +++ b/patches/6.13/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 977d6a4eccbe4a54e06a510a7b553d9340193426 Mon Sep 17 00:00:00 2001 +From 04e4e3bd36af14f0d6d9eabbfd9b6090247e4eba Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 18485170d51b..66d1b9e8aa9d 100644 -- 2.48.1 -From 0a3a25ae02896d38edd23b947a72b9fb587b159f Mon Sep 17 00:00:00 2001 +From 438f8d54a08f27470165575040d3ee51cd943e52 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.13/0016-rtc.patch b/patches/6.13/0015-rtc.patch similarity index 98% rename from patches/6.13/0016-rtc.patch rename to patches/6.13/0015-rtc.patch index 2803a2da09..857f0eaeb9 100644 --- a/patches/6.13/0016-rtc.patch +++ b/patches/6.13/0015-rtc.patch @@ -1,4 +1,4 @@ -From 4d3b956038eac47f59133a636a71b73b21fd1bb0 Mon Sep 17 00:00:00 2001 +From 8b87bc2d8d00488493dc389fe768d6f9ad034fff Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From a8cb63e3163d53b3ac1110973e358bce613bc9ce Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 01:50:34 +0100 Subject: [PATCH 087/236] Update Arch kernel to v6.13.6 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3-oemb.patch | 1 - pkg/arch/kernel/0002-surface3.patch | 1 + pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- .../kernel/0007-surface-sam-over-hid.patch | 1 - pkg/arch/kernel/0007-surface-sam.patch | 1 + pkg/arch/kernel/0008-surface-button.patch | 1 - .../kernel/0008-surface-sam-over-hid.patch | 1 + pkg/arch/kernel/0009-surface-button.patch | 1 + pkg/arch/kernel/0009-surface-typecover.patch | 1 - pkg/arch/kernel/0010-surface-shutdown.patch | 1 - pkg/arch/kernel/0010-surface-typecover.patch | 1 + pkg/arch/kernel/0011-surface-gpe.patch | 1 - pkg/arch/kernel/0011-surface-shutdown.patch | 1 + pkg/arch/kernel/0012-cameras.patch | 1 - pkg/arch/kernel/0012-surface-gpe.patch | 1 + pkg/arch/kernel/0013-amd-gpio.patch | 1 - pkg/arch/kernel/0013-cameras.patch | 1 + pkg/arch/kernel/0014-amd-gpio.patch | 1 + pkg/arch/kernel/0014-rtc.patch | 1 - pkg/arch/kernel/0015-rtc.patch | 1 + pkg/arch/kernel/PKGBUILD | 52 ++++++++++--------- pkg/arch/kernel/surface.config | 2 +- 26 files changed, 43 insertions(+), 40 deletions(-) delete mode 120000 pkg/arch/kernel/0002-surface3-oemb.patch create mode 120000 pkg/arch/kernel/0002-surface3.patch delete mode 120000 pkg/arch/kernel/0007-surface-sam-over-hid.patch create mode 120000 pkg/arch/kernel/0007-surface-sam.patch delete mode 120000 pkg/arch/kernel/0008-surface-button.patch create mode 120000 pkg/arch/kernel/0008-surface-sam-over-hid.patch create mode 120000 pkg/arch/kernel/0009-surface-button.patch delete mode 120000 pkg/arch/kernel/0009-surface-typecover.patch delete mode 120000 pkg/arch/kernel/0010-surface-shutdown.patch create mode 120000 pkg/arch/kernel/0010-surface-typecover.patch delete mode 120000 pkg/arch/kernel/0011-surface-gpe.patch create mode 120000 pkg/arch/kernel/0011-surface-shutdown.patch delete mode 120000 pkg/arch/kernel/0012-cameras.patch create mode 120000 pkg/arch/kernel/0012-surface-gpe.patch delete mode 120000 pkg/arch/kernel/0013-amd-gpio.patch create mode 120000 pkg/arch/kernel/0013-cameras.patch create mode 120000 pkg/arch/kernel/0014-amd-gpio.patch delete mode 120000 pkg/arch/kernel/0014-rtc.patch create mode 120000 pkg/arch/kernel/0015-rtc.patch diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 5f9c78e8d0..6b2cd21cd9 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.12/0001-secureboot.patch \ No newline at end of file +../../../patches/6.13/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3-oemb.patch b/pkg/arch/kernel/0002-surface3-oemb.patch deleted file mode 120000 index 3ab3eddcb5..0000000000 --- a/pkg/arch/kernel/0002-surface3-oemb.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0002-surface3-oemb.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3.patch b/pkg/arch/kernel/0002-surface3.patch new file mode 120000 index 0000000000..9d51dc679e --- /dev/null +++ b/pkg/arch/kernel/0002-surface3.patch @@ -0,0 +1 @@ +../../../patches/6.13/0002-surface3.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index d39603075b..274642101f 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.12/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.13/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index d0bc43e2c2..78aac27bab 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.12/0004-ath10k.patch \ No newline at end of file +../../../patches/6.13/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index 383c962da1..46e4786335 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.12/0005-ipts.patch \ No newline at end of file +../../../patches/6.13/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index ed8f03666c..2c4cedf34a 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.12/0006-ithc.patch \ No newline at end of file +../../../patches/6.13/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam-over-hid.patch b/pkg/arch/kernel/0007-surface-sam-over-hid.patch deleted file mode 120000 index e67edaf50a..0000000000 --- a/pkg/arch/kernel/0007-surface-sam-over-hid.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0007-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch new file mode 120000 index 0000000000..9d50d75414 --- /dev/null +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -0,0 +1 @@ +../../../patches/6.13/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-button.patch b/pkg/arch/kernel/0008-surface-button.patch deleted file mode 120000 index 5fa465409e..0000000000 --- a/pkg/arch/kernel/0008-surface-button.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0008-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch new file mode 120000 index 0000000000..d6c5aa570e --- /dev/null +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -0,0 +1 @@ +../../../patches/6.13/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch new file mode 120000 index 0000000000..9a3c5cece4 --- /dev/null +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -0,0 +1 @@ +../../../patches/6.13/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-typecover.patch b/pkg/arch/kernel/0009-surface-typecover.patch deleted file mode 120000 index 5020908f2a..0000000000 --- a/pkg/arch/kernel/0009-surface-typecover.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0009-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-shutdown.patch b/pkg/arch/kernel/0010-surface-shutdown.patch deleted file mode 120000 index 1392efb661..0000000000 --- a/pkg/arch/kernel/0010-surface-shutdown.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0010-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch new file mode 120000 index 0000000000..c15115cb19 --- /dev/null +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -0,0 +1 @@ +../../../patches/6.13/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-gpe.patch b/pkg/arch/kernel/0011-surface-gpe.patch deleted file mode 120000 index 2ea93f4800..0000000000 --- a/pkg/arch/kernel/0011-surface-gpe.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0011-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch new file mode 120000 index 0000000000..586b5370e7 --- /dev/null +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -0,0 +1 @@ +../../../patches/6.13/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-cameras.patch b/pkg/arch/kernel/0012-cameras.patch deleted file mode 120000 index d29732717e..0000000000 --- a/pkg/arch/kernel/0012-cameras.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0012-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch new file mode 120000 index 0000000000..154bf83cd7 --- /dev/null +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -0,0 +1 @@ +../../../patches/6.13/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-amd-gpio.patch b/pkg/arch/kernel/0013-amd-gpio.patch deleted file mode 120000 index 4b9166a735..0000000000 --- a/pkg/arch/kernel/0013-amd-gpio.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0013-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch new file mode 120000 index 0000000000..79798f0153 --- /dev/null +++ b/pkg/arch/kernel/0013-cameras.patch @@ -0,0 +1 @@ +../../../patches/6.13/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch new file mode 120000 index 0000000000..57b3a9beb7 --- /dev/null +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -0,0 +1 @@ +../../../patches/6.13/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-rtc.patch b/pkg/arch/kernel/0014-rtc.patch deleted file mode 120000 index 1d6c7da4e7..0000000000 --- a/pkg/arch/kernel/0014-rtc.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.12/0014-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch new file mode 120000 index 0000000000..ca9aa24baf --- /dev/null +++ b/pkg/arch/kernel/0015-rtc.patch @@ -0,0 +1 @@ +../../../patches/6.13/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index d229b2faf9..e88dfd420b 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.12.7.arch1 +pkgver=6.13.6.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -37,43 +37,45 @@ source=( surface.config # surface specific options arch.config # config changes for linux-surface kernel 0001-secureboot.patch - 0002-surface3-oemb.patch + 0002-surface3.patch 0003-mwifiex.patch 0004-ath10k.patch 0005-ipts.patch 0006-ithc.patch - 0007-surface-sam-over-hid.patch - 0008-surface-button.patch - 0009-surface-typecover.patch - 0010-surface-shutdown.patch - 0011-surface-gpe.patch - 0012-cameras.patch - 0013-amd-gpio.patch - 0014-rtc.patch + 0007-surface-sam.patch + 0008-surface-sam-over-hid.patch + 0009-surface-button.patch + 0010-surface-typecover.patch + 0011-surface-shutdown.patch + 0012-surface-gpe.patch + 0013-cameras.patch + 0014-amd-gpio.patch + 0015-rtc.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('0fd0d052ca0b649ed6e12ca883ca9bdf49bd35c60372e4c34fe24019c442466a' +sha256sums=('9c6c97b099ac0340c12355f58c553cbf2e27a89e274c6d0a188d5b4fe1700ccc' 'a6a234cd982d21f0d7daa3ba921293e450abd87ff5d7474d4a153b3f34cfabc5' '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '979c23063ac85900deb62d6ab54f250bab5f9bae83dbe4082145b86772570dff' - 'eef74faedb785a3b484909b820d447b793b0b2d6eaf1aecc3ab9ee94a9ece48e' - '9284772ff36b0389b60cfeddab3a378ecb57ae1420183b87c71266a87def787d' - '93631c1e0670c5a6e185b136bbe21866be6be7648ca0a969e90a9fb337c70214' - '5d5a75e191e76a79100566ca7e96e4de45430fddd3d195ad78da5966499903b1' - 'd5e9d28884dc5b651d8d4e69e2798be3d1fdea9fba3da63007fa373a1bb1eb7e' - '7f1cda3bba5d8e8349f0d2524d502571170d4e2ef9204c41f9ebe705ada627cc' - '845a2045280e4725d925767dd3098700b45f85035c0a5072cc81a77178235223' - '16549d3d4f461e0f11d954e70a626ae319760fba2e10cf2f4804a670b1b7a418' - 'bb042ae3aedceb366785e8043e67e77dce19c0ae0e558ddae1bea0c50603848c' - '2dd074e9ba0f380fe5334d809e98fc351b07a533b7bc7d36cbd357e7fadea784' - 'df6c27af42db207a19c0c69210af6f4c26070d16989dd833dfebd80ac3990b17' - '0109e2dfa394f9918a5b73fbe98c634e05413f257ad19cc78c73baacd9f04ea5' - 'b247a7aa0f9f9d844dc7c8fba438b9abb845b89da161c498ae72d2d62bcdbeb0') + '12cb726d3ef7caeb7a8fb29488d26a33725f485c47a067ed3ff7b73a338478de' + 'eb5f12d39c6ddedf00de709dcddb2a5df08ce0f01d831ab6b0fc7cd816a9110c' + '013aacb2ef594f5b484b788799cee2e891827e09660ef119c157494141076155' + 'a3bca0c32b90c9ded47797c21952119d81bb7d0c6181c70103846e9eb8da3d45' + '2943ac9984fd05f75a31f53f9176837ba59caf72cca6105b4df2a9f72d95ceb4' + 'f389649f7c7286252e2ef531a4cfc69c12bb1f08f1c95bf81187c67e272f13b5' + 'da69177bc18a3897ec64906bafde1d37faf378604185ee74e64d5e5a7ef4b9df' + 'fa3614f0115694056631d471902d8bc40a7ee6063059cfd7210a6ca98a577041' + '9d3bf1705dc162a50e241bff1472aad05161c4656d19234f7ae61238929ad39b' + 'b7f221ddf8f4c1005876b286a17d25625657f88ed02bd6e12ef7f400c63f473a' + '2da0d1990890f4e01ffbf58b832d6e4834837ffb4a6f6cac8da696078449c8d6' + 'af784ad1d215236eae70597a723c3b96725d1416c3e6fa261fe731151e52df3f' + '6e46d9b1a6f1d91003438129ec61ffca1adf8a0b0b2a694dd7759239eb72c031' + '91bff8fa20a8cd1e000fd0f151d7b61df234a416add957e330ec885b8552b9fd' + '9afca88db82adddef56f88217f5d5273b05a449e11b702bbf0dadc4d28f93c58') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index bc3c4bde54..dbabc66c35 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.12.config \ No newline at end of file +../../../configs/surface-6.13.config \ No newline at end of file From 4b678ad16e0637dc1c4afbcdca71b1833c7d0d24 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 01:55:12 +0100 Subject: [PATCH 088/236] Update actions --- .github/workflows/arch.yml | 10 +++++----- .github/workflows/debian.yml | 10 +++++----- .github/workflows/fedora-40.yml | 10 +++++----- .github/workflows/fedora-41.yml | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/arch.yml b/.github/workflows/arch.yml index ff9b15e58c..87d3e269b8 100644 --- a/.github/workflows/arch.yml +++ b/.github/workflows/arch.yml @@ -25,7 +25,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize containers run: | @@ -64,7 +64,7 @@ jobs: bash ./.github/scripts/package/arch.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: arch-latest path: pkg/arch/kernel/release @@ -76,7 +76,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: arch-latest path: arch-latest @@ -96,10 +96,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: arch-latest path: arch-latest diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 19a0ebc731..086de5c412 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -25,7 +25,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize containers run: | @@ -64,7 +64,7 @@ jobs: bash ./.github/scripts/package/debian.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: debian-latest path: pkg/debian/release @@ -76,7 +76,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: debian-latest path: debian-latest @@ -96,10 +96,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: debian-latest path: debian-latest diff --git a/.github/workflows/fedora-40.yml b/.github/workflows/fedora-40.yml index aca862de0f..7026a2f8c3 100644 --- a/.github/workflows/fedora-40.yml +++ b/.github/workflows/fedora-40.yml @@ -26,7 +26,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize containers run: | @@ -65,7 +65,7 @@ jobs: bash ./.github/scripts/package/fedora.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: fedora-${{ env.FEDORA }}-latest path: pkg/fedora/kernel-surface/out/x86_64 @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest @@ -97,10 +97,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest diff --git a/.github/workflows/fedora-41.yml b/.github/workflows/fedora-41.yml index a3e9066f21..81232c6b53 100644 --- a/.github/workflows/fedora-41.yml +++ b/.github/workflows/fedora-41.yml @@ -26,7 +26,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize containers run: | @@ -65,7 +65,7 @@ jobs: bash ./.github/scripts/package/fedora.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: fedora-${{ env.FEDORA }}-latest path: pkg/fedora/kernel-surface/out/x86_64 @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest @@ -97,10 +97,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest From 7268c799404686a24213e7353d17af79f72d488b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 01:56:40 +0100 Subject: [PATCH 089/236] Update Debian kernel to v6.13.6 --- pkg/debian/kernel/version.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 9a0c4ee86d..aa7ce3cf73 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.12.3" -KERNEL_REVISION="2" +KERNEL_VERSION="6.13.6" +KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 7386b54e06bd7e277059ea3f8abb2df0d8fdf1b3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 01:57:48 +0100 Subject: [PATCH 090/236] Update Fedora kernels to v6.13.6 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 83cec0a2ee..51200aecde 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.12.7-0" +PACKAGE_TAG = "kernel-6.13.6-0" ## ## The release number of the modified kernel package. From e714f7e3714d8cdb33ce25656eccef3172291cdd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 14:58:37 +0100 Subject: [PATCH 091/236] pkg/fedora: Add Fedora specific rebase of patches Fedora v6.13 kernels include downstream intel THC patches. This causes our patches to not apply correctly. Therefore, temporarily add a Fedora-specific rebase of the patches. --- patches/6.13-fedora/0001-secureboot.patch | 112 + patches/6.13-fedora/0002-surface3.patch | 234 ++ patches/6.13-fedora/0003-mwifiex.patch | 400 ++ patches/6.13-fedora/0004-ath10k.patch | 120 + patches/6.13-fedora/0005-ipts.patch | 3241 +++++++++++++++++ patches/6.13-fedora/0006-ithc.patch | 2771 ++++++++++++++ patches/6.13-fedora/0007-surface-sam.patch | 223 ++ .../0008-surface-sam-over-hid.patch | 308 ++ patches/6.13-fedora/0009-surface-button.patch | 149 + .../6.13-fedora/0010-surface-typecover.patch | 575 +++ .../6.13-fedora/0011-surface-shutdown.patch | 97 + patches/6.13-fedora/0012-surface-gpe.patch | 51 + patches/6.13-fedora/0013-cameras.patch | 734 ++++ patches/6.13-fedora/0014-amd-gpio.patch | 109 + patches/6.13-fedora/0015-rtc.patch | 110 + .../kernel-surface/build-linux-surface.py | 2 +- 16 files changed, 9235 insertions(+), 1 deletion(-) create mode 100644 patches/6.13-fedora/0001-secureboot.patch create mode 100644 patches/6.13-fedora/0002-surface3.patch create mode 100644 patches/6.13-fedora/0003-mwifiex.patch create mode 100644 patches/6.13-fedora/0004-ath10k.patch create mode 100644 patches/6.13-fedora/0005-ipts.patch create mode 100644 patches/6.13-fedora/0006-ithc.patch create mode 100644 patches/6.13-fedora/0007-surface-sam.patch create mode 100644 patches/6.13-fedora/0008-surface-sam-over-hid.patch create mode 100644 patches/6.13-fedora/0009-surface-button.patch create mode 100644 patches/6.13-fedora/0010-surface-typecover.patch create mode 100644 patches/6.13-fedora/0011-surface-shutdown.patch create mode 100644 patches/6.13-fedora/0012-surface-gpe.patch create mode 100644 patches/6.13-fedora/0013-cameras.patch create mode 100644 patches/6.13-fedora/0014-amd-gpio.patch create mode 100644 patches/6.13-fedora/0015-rtc.patch diff --git a/patches/6.13-fedora/0001-secureboot.patch b/patches/6.13-fedora/0001-secureboot.patch new file mode 100644 index 0000000000..cdc2745e60 --- /dev/null +++ b/patches/6.13-fedora/0001-secureboot.patch @@ -0,0 +1,112 @@ +From 94ade6781f154dfd06900517a4c18d20aad64c70 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.48.1 + +From 2bb6335216913bc247e2bc41f1ea2ff0a8981a4a Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 3872bc6ec49d..e322b97879c2 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3074,6 +3074,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 10a01af63a80..e53e4a86e4cc 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1434,6 +1435,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1492,3 +1499,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.48.1 + diff --git a/patches/6.13-fedora/0002-surface3.patch b/patches/6.13-fedora/0002-surface3.patch new file mode 100644 index 0000000000..a87871a25a --- /dev/null +++ b/patches/6.13-fedora/0002-surface3.patch @@ -0,0 +1,234 @@ +From 5e29598180e78ed9adbe88731ce2bbc9affb0ccc Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3 +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index 6c8fb7a4dde4..22797a53f4d8 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.48.1 + +From cd79bb7fed2cd0269d368cc4dea3194564262883 Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Fri, 6 Dec 2019 23:10:30 +0900 +Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by + default + +On Arch Linux kernel at least after 4.19, touch input is broken after suspend +(s2idle). + + kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + +On recent stable Arch Linux kernel (at least after 5.1), touch input will +crash after the first touch. + + kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue + +I found on an affected system (Arch Linux kernel, etc.), the touchscreen +driver uses DMA mode by default. Then, we found some kernels with different +kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel +chromeos-4.19 [2]) will use PIO mode by default and no such issues there. + +So, this commit disables DMA mode on the touchscreen driver side as a quick +workaround to avoid touch input crash. +We may need to properly set up DMA mode to use the touchscreen driver with +DMA mode. + +You can still switch DMA/PIO mode if you want: + + switch to DMA mode (maybe broken) + echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma + back to PIO mode + echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma + +Link to issue: https://github.com/jakeday/linux-surface/issues/596 + +References: +[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config +[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 + +Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. +This commit made the driver use PIO by default and no touch input crash. +Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default +even without this commit. After this commit, it still uses PIO and confirmed +no functional changes regarding touch input. + +More details: + We can confirm which mode the touchscreen driver uses; first, enable + debug output: + + echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + + Then, try to make a touch input and see dmesg log + + (On Arch Linux kernel, uses DMA) + kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA + kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 + c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + + (On the kernels I referenced above, uses PIO) + kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO + kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 + 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Note (2025-03-08): This patch was originally dropped due to the +comments in [3]. However, according to the commments in [4] it is still +required. + +[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a +[4]: https://github.com/linux-surface/linux-surface/issues/1184 + +Patchset: surface3 +--- + drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c +index 6074b7730e86..6aa3e1d6f160 100644 +--- a/drivers/input/touchscreen/surface3_spi.c ++++ b/drivers/input/touchscreen/surface3_spi.c +@@ -25,6 +25,12 @@ + #define SURFACE3_REPORT_TOUCH 0xd2 + #define SURFACE3_REPORT_PEN 0x16 + ++bool use_dma = false; ++module_param(use_dma, bool, 0644); ++MODULE_PARM_DESC(use_dma, ++ "Disable DMA mode if you encounter touch input crash. " ++ "(default: false, disabled to avoid crash)"); ++ + struct surface3_ts_data { + struct spi_device *spi; + struct gpio_desc *gpiod_rst[2]; +@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) + return 0; + } + ++static bool surface3_spi_can_dma(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) ++{ ++ return use_dma; ++} ++ + static int surface3_spi_probe(struct spi_device *spi) + { + struct surface3_ts_data *data; +@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) + if (error) + return error; + ++ /* ++ * Set up DMA ++ * ++ * TODO: Currently, touch input with DMA seems to be broken. ++ * On 4.19 LTS, touch input will crash after suspend. ++ * On recent stable kernel (at least after 5.1), touch input will crash after ++ * the first touch. No problem with PIO on those kernels. ++ * Maybe we need to configure DMA here. ++ * ++ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 ++ */ ++ spi->controller->can_dma = surface3_spi_can_dma; ++ + return 0; + } + +-- +2.48.1 + diff --git a/patches/6.13-fedora/0003-mwifiex.patch b/patches/6.13-fedora/0003-mwifiex.patch new file mode 100644 index 0000000000..bc0e6225d1 --- /dev/null +++ b/patches/6.13-fedora/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From c428669fce7eca5a597c0e7b0072e930f4895819 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.48.1 + +From 72f5a2ee698b9d344ea097930f2a0b7b617951d7 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.48.1 + +From 964b1e54a083db2d78ba2352f706d297ed8b13c4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 72e85673b709..110c983dfd53 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -440,6 +441,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -3869,6 +3871,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.48.1 + diff --git a/patches/6.13-fedora/0004-ath10k.patch b/patches/6.13-fedora/0004-ath10k.patch new file mode 100644 index 0000000000..5af6e07db4 --- /dev/null +++ b/patches/6.13-fedora/0004-ath10k.patch @@ -0,0 +1,120 @@ +From d8bf22111250427ec82a7918528346c714d39e24 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index b3294287bce1..2936fdae823c 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.48.1 + diff --git a/patches/6.13-fedora/0005-ipts.patch b/patches/6.13-fedora/0005-ipts.patch new file mode 100644 index 0000000000..6aa6b4c099 --- /dev/null +++ b/patches/6.13-fedora/0005-ipts.patch @@ -0,0 +1,3241 @@ +From 6b36fb0eff720194a680dd6d66fee5c47acff46c Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6589635f8ba3..a1df48a434e2 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.48.1 + +From 468c032c6956af12d83aa0c7d86e2fd1a47221f3 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 9ab5371c3538..1839a831a89f 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -40,6 +40,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -1903,6 +1910,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2201,6 +2211,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4509,6 +4522,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4544,6 +4569,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.48.1 + +From 3e0542848e2fc70847d83533e082ab9cbc46d711 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index c57927529f8a..9aabcf4241c6 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1388,4 +1388,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 482b096eea28..2024681e72fb 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,3 +173,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.48.1 + diff --git a/patches/6.13-fedora/0006-ithc.patch b/patches/6.13-fedora/0006-ithc.patch new file mode 100644 index 0000000000..231b2449e9 --- /dev/null +++ b/patches/6.13-fedora/0006-ithc.patch @@ -0,0 +1,2771 @@ +From acb1100081559166a23b76a7151b958f0b43a740 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 466c1412dd45..565686813588 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.48.1 + +From 860404c8e0c0789f6dcc29cb82ff913a9276bd63 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 9aabcf4241c6..f7ee006bff6d 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1390,4 +1390,6 @@ source "drivers/hid/intel-thc-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 2024681e72fb..f5dcee37fe8a 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -175,3 +175,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.48.1 + diff --git a/patches/6.13-fedora/0007-surface-sam.patch b/patches/6.13-fedora/0007-surface-sam.patch new file mode 100644 index 0000000000..ed3c409fd7 --- /dev/null +++ b/patches/6.13-fedora/0007-surface-sam.patch @@ -0,0 +1,223 @@ +From 1c5d9203a4fc782d1934187ccb6e454a6a110b9c Mon Sep 17 00:00:00 2001 +From: Lukas +Date: Sat, 8 Mar 2025 22:00:46 +0100 +Subject: [PATCH] platform/surface: aggregator_registry: Add support for + Surface Pro 11 + +Add Support for the Surface Pro 11. As the SAM clients are equivalent to +the Surface Pro 9, reuse its nodes. + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index d4f32ad66530..08b4ef382fab 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -371,7 +371,7 @@ static const struct software_node *ssam_node_group_sp8[] = { + NULL, + }; + +-/* Devices for Surface Pro 9 (Intel/x86) and 10 */ ++/* Devices for Surface Pro 9 (Intel/x86), 10 and 11 */ + static const struct software_node *ssam_node_group_sp9[] = { + &ssam_node_root, + &ssam_node_hub_kip, +@@ -430,6 +430,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Pro 10 */ + { "MSHW0510", (unsigned long)ssam_node_group_sp9 }, + ++ /* Surface Pro 11 */ ++ { "MSHW0583", (unsigned long)ssam_node_group_sp9 }, ++ + /* Surface Book 2 */ + { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, + +-- +2.48.1 + +From 6250d3bbd6a70dbbbb44856314facc9649f3784c Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 17 Jun 2022 02:14:00 +0200 +Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator + Module + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/rtc/Kconfig | 7 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 drivers/rtc/rtc-surface.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index a60bcc791a48..2de96e4c1ba6 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1383,6 +1383,13 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_SURFACE ++ tristate "Microsoft Surface Aggregator RTC" ++ depends on SURFACE_AGGREGATOR ++ depends on SURFACE_AGGREGATOR_BUS ++ help ++ TODO ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 489b4ab07068..061afa9db5b6 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -180,6 +180,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o + obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o + obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o + obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o ++obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o +diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c +new file mode 100644 +index 000000000000..f6c17c4e98d5 +--- /dev/null ++++ b/drivers/rtc/rtc-surface.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * AC driver for 7th-generation Microsoft Surface devices via Surface System ++ * Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2019-2021 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct surface_rtc { ++ struct ssam_device *sdev; ++ struct rtc_device *rtc; ++}; ++ ++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x10, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x0f, ++}); ++ ++static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) ++{ ++ __le32 time_le; ++ int status; ++ ++ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); ++ if (status) ++ return status; ++ ++ *time = le32_to_cpu(time_le); ++ return 0; ++} ++ ++static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) ++{ ++ __le32 time_le = cpu_to_le32(time); ++ ++ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); ++} ++ ++static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ int status; ++ u32 time; ++ ++ status = ssam_rtc_get_unix_time(srtc, &time); ++ if (status) ++ return status; ++ ++ rtc_time64_to_tm(time, tm); ++ return 0; ++} ++ ++static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ time64_t time = rtc_tm_to_time64(tm); ++ ++ return ssam_rtc_set_unix_time(srtc, (u32)time); ++} ++ ++static const struct rtc_class_ops surface_rtc_ops = { ++ .read_time = surface_rtc_read_time, ++ .set_time = surface_rtc_set_time, ++}; ++ ++static int surface_rtc_probe(struct ssam_device *sdev) ++{ ++ struct surface_rtc *srtc; ++ ++ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->sdev = sdev; ++ ++ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); ++ if (IS_ERR(srtc->rtc)) ++ return PTR_ERR(srtc->rtc); ++ ++ srtc->rtc->ops = &surface_rtc_ops; ++ srtc->rtc->range_max = U32_MAX; ++ ++ ssam_device_set_drvdata(sdev, srtc); ++ ++ return devm_rtc_register_device(srtc->rtc); ++} ++ ++static void surface_rtc_remove(struct ssam_device *sdev) ++{ ++ /* Device-managed allocations take care of everything... */ ++} ++ ++static const struct ssam_device_id surface_rtc_match[] = { ++ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, surface_rtc_match); ++ ++static struct ssam_device_driver surface_rtc_driver = { ++ .probe = surface_rtc_probe, ++ .remove = surface_rtc_remove, ++ .match_table = surface_rtc_match, ++ .driver = { ++ .name = "surface_rtc", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(surface_rtc_driver); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.48.1 + diff --git a/patches/6.13-fedora/0008-surface-sam-over-hid.patch b/patches/6.13-fedora/0008-surface-sam-over-hid.patch new file mode 100644 index 0000000000..491b74de2e --- /dev/null +++ b/patches/6.13-fedora/0008-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From 801aead8a7443382f7c4c5ffea712cfda1ad102c Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index d2499f302b50..77ce5ec3dd9e 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -661,6 +661,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -762,6 +783,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.48.1 + +From f849b992c262e89b05810602390e41da0e9f185d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.48.1 + diff --git a/patches/6.13-fedora/0009-surface-button.patch b/patches/6.13-fedora/0009-surface-button.patch new file mode 100644 index 0000000000..8429495b40 --- /dev/null +++ b/patches/6.13-fedora/0009-surface-button.patch @@ -0,0 +1,149 @@ +From 5259336f8461ac0b8d0e625b614d61274e70be09 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index b8cad415c62c..43b5d56383e3 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.48.1 + +From 50d8655cc723db3b6462bfbc4c711694da923ae6 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.48.1 + diff --git a/patches/6.13-fedora/0010-surface-typecover.patch b/patches/6.13-fedora/0010-surface-typecover.patch new file mode 100644 index 0000000000..f22e4de76f --- /dev/null +++ b/patches/6.13-fedora/0010-surface-typecover.patch @@ -0,0 +1,575 @@ +From 0f982a17fd6d3c96be3c3dd066a6250211666984 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 027479179f09..ee5a6bf5452d 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.48.1 + +From 00663433f93be502d076cb5d66d0ec957ddeff29 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e50887a6d22c..4ce18f21a141 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -35,7 +35,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -73,12 +77,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -176,6 +183,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -220,6 +229,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -410,6 +420,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1759,6 +1779,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1782,6 +1865,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1820,8 +1906,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); +@@ -1830,8 +1918,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1881,6 +1971,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2304,6 +2395,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.48.1 + +From 3d6dc5f4bc862a62c0a1316e066d9d07ca17c4e1 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 4ce18f21a141..f5e4d52bd2eb 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -85,6 +86,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -422,6 +425,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1403,6 +1407,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1430,6 +1437,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1451,6 +1473,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1458,6 +1481,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1467,11 +1503,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1646,6 +1692,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1694,6 +1776,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1779,30 +1868,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1811,8 +1876,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1949,13 +2015,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1964,12 +2041,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.48.1 + diff --git a/patches/6.13-fedora/0011-surface-shutdown.patch b/patches/6.13-fedora/0011-surface-shutdown.patch new file mode 100644 index 0000000000..575b56161a --- /dev/null +++ b/patches/6.13-fedora/0011-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 222392358de9542132abcb173bfdc1d8a47deee3 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 35270172c833..529779994ef6 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 8aba731f9ce3..5e02a01fefc2 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6338,3 +6338,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index f05903dd7695..d1e38fdaf8bb 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -476,6 +476,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.48.1 + diff --git a/patches/6.13-fedora/0012-surface-gpe.patch b/patches/6.13-fedora/0012-surface-gpe.patch new file mode 100644 index 0000000000..b4a3183c28 --- /dev/null +++ b/patches/6.13-fedora/0012-surface-gpe.patch @@ -0,0 +1,51 @@ +From df5ea6881e7fd0d73be29469721377d5ecbc4bd7 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index b359413903b1..b4496db79f39 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.48.1 + diff --git a/patches/6.13-fedora/0013-cameras.patch b/patches/6.13-fedora/0013-cameras.patch new file mode 100644 index 0000000000..9bf6e1261f --- /dev/null +++ b/patches/6.13-fedora/0013-cameras.patch @@ -0,0 +1,734 @@ +From 6675cd092b80f34b8697aa9012855e351eb704db Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index d6265ddc87ef..2a5fcdff4d69 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2214,6 +2214,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.48.1 + +From d225b017ed8cadd981353e1cf114cddf79444cfc Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 1839a831a89f..ebd7aa6b9038 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -45,6 +45,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -214,12 +221,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -1911,6 +1920,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2211,6 +2223,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4522,6 +4537,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4569,6 +4596,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.48.1 + +From 9c19e6347c9da54ab936be79799c010c06710aa4 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 81ac4c691963..f453c9043042 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.48.1 + +From 46a21f6b29916e6e600eefb53c054bf684c34e49 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 09fff213b091..ce641eb45de6 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ { } ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity ^= GPIO_ACTIVE_LOW; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) +-- +2.48.1 + +From 0a96da6ea51e6117da7bc09ec2b1a4825bf3f1d0 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.48.1 + +From 5be6985f9a839a162a69b8cd73345fb77ccceea2 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index f19c8adf2c61..923ed1b5ab8b 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.48.1 + +From d625f41c3c85ffc29c9f11a6040324052edebc0a Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index f453c9043042..b8ad6b413e8b 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.48.1 + +From 26cea0a675dd2392b0fc23d9b1f9633e131e6b6c Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.48.1 + +From 61c8e3ff365f40be6c82f7e0b9895a60159e2c94 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index b784bb74a837..f8d8fcfacac2 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -941,6 +941,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 18afbb5a23ee..a1d16c0af82d 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.48.1 + +From 62551f0c278803ba20e5ecbfe600f49d675d0855 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.48.1 + diff --git a/patches/6.13-fedora/0014-amd-gpio.patch b/patches/6.13-fedora/0014-amd-gpio.patch new file mode 100644 index 0000000000..8b1a8b493a --- /dev/null +++ b/patches/6.13-fedora/0014-amd-gpio.patch @@ -0,0 +1,109 @@ +From 2b479b02392b0a54e6e8c816c43db4f324f7f3da Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 18485170d51b..66d1b9e8aa9d 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1172,6 +1173,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1228,6 +1240,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.48.1 + +From f92cb8388023fb303b14dfcfb65782834ab4b172 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 66d1b9e8aa9d..741e05190b41 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1175,12 +1175,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.48.1 + diff --git a/patches/6.13-fedora/0015-rtc.patch b/patches/6.13-fedora/0015-rtc.patch new file mode 100644 index 0000000000..924e6ce16b --- /dev/null +++ b/patches/6.13-fedora/0015-rtc.patch @@ -0,0 +1,110 @@ +From b79ca491e86cc6bf4c60988f3dc9a332288340f1 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 825c2a8acea4..74612088ac5f 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.48.1 + diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 51200aecde..93ca2d1829 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -79,7 +79,7 @@ kernel_major = ".".join(kernel_version.split(".")[:2]) # Determine the patches directory and config file. -patches = linux_surface / "patches" / kernel_major +patches = linux_surface / "patches" / f"{kernel_major}-fedora" config = linux_surface / "configs" / ("surface-%s.config" % kernel_major) sb_cert = script / "secureboot" / "MOK.crt" From 0e17ba8007708620dd759cab3f107ea033514c43 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Mar 2025 15:30:58 +0100 Subject: [PATCH 092/236] Add missing config option --- configs/surface-6.13.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/surface-6.13.config b/configs/surface-6.13.config index 05628a9957..d58d539727 100644 --- a/configs/surface-6.13.config +++ b/configs/surface-6.13.config @@ -22,6 +22,8 @@ CONFIG_CHARGER_SURFACE=m CONFIG_SENSORS_SURFACE_TEMP=m CONFIG_SENSORS_SURFACE_FAN=m +CONFIG_RTC_DRV_SURFACE=m + ## ## Surface Hotplug ## From b057a2f28c98ec18c21b9cac0fa599bcc08b5f61 Mon Sep 17 00:00:00 2001 From: tabletseeker <148603424+tabletseeker@users.noreply.github.com> Date: Tue, 1 Apr 2025 18:17:47 +0000 Subject: [PATCH 093/236] Adding patches for v6.14 --- patches/6.14/0001-secureboot.patch | 112 + patches/6.14/0002-surface3-oemb.patch | 101 + patches/6.14/0003-mwifiex.patch | 400 +++ patches/6.14/0004-ath10k.patch | 120 + patches/6.14/0005-ipts.patch | 3251 ++++++++++++++++++ patches/6.14/0006-ithc.patch | 2783 +++++++++++++++ patches/6.14/0007-surface-sam-over-hid.patch | 308 ++ patches/6.14/0008-surface-button.patch | 149 + patches/6.14/0009-surface-typecover.patch | 575 ++++ patches/6.14/0010-surface-shutdown.patch | 104 + patches/6.14/0011-surface-gpe.patch | 51 + patches/6.14/0013-amd-gpio.patch | 109 + patches/6.14/0014-rtc.patch | 110 + 13 files changed, 8173 insertions(+) create mode 100644 patches/6.14/0001-secureboot.patch create mode 100644 patches/6.14/0002-surface3-oemb.patch create mode 100644 patches/6.14/0003-mwifiex.patch create mode 100644 patches/6.14/0004-ath10k.patch create mode 100644 patches/6.14/0005-ipts.patch create mode 100644 patches/6.14/0006-ithc.patch create mode 100644 patches/6.14/0007-surface-sam-over-hid.patch create mode 100644 patches/6.14/0008-surface-button.patch create mode 100644 patches/6.14/0009-surface-typecover.patch create mode 100644 patches/6.14/0010-surface-shutdown.patch create mode 100644 patches/6.14/0011-surface-gpe.patch create mode 100644 patches/6.14/0013-amd-gpio.patch create mode 100644 patches/6.14/0014-rtc.patch diff --git a/patches/6.14/0001-secureboot.patch b/patches/6.14/0001-secureboot.patch new file mode 100644 index 0000000000..addb86e813 --- /dev/null +++ b/patches/6.14/0001-secureboot.patch @@ -0,0 +1,112 @@ +From bbcfb18eb05bd92e4501ca35bdfd558c849ddeda Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.47.1 + +From 9a796344897d077f1fc977ab026315c2cfcd3960 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index d401577b5a6a..5a812e0b740a 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3066,6 +3066,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index e35829d36039..6d54eb03b63d 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1426,6 +1427,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1484,3 +1491,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.47.1 + diff --git a/patches/6.14/0002-surface3-oemb.patch b/patches/6.14/0002-surface3-oemb.patch new file mode 100644 index 0000000000..ab40dd606c --- /dev/null +++ b/patches/6.14/0002-surface3-oemb.patch @@ -0,0 +1,101 @@ +From 2ce5cf2a597c9015c64ea9f386a396f97b8589c6 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-oemb +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index c15ed7a12784..1ec8edb5aafa 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.47.1 + diff --git a/patches/6.14/0003-mwifiex.patch b/patches/6.14/0003-mwifiex.patch new file mode 100644 index 0000000000..523a943588 --- /dev/null +++ b/patches/6.14/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From ed54461506b98c1bc8ae8dc5f7385de1f900ed0b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.47.1 + +From a93a869673e056cf2a2c46b9438edaca8f5e2645 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.47.1 + +From bcc616a02ed2a9e059d2e7a1dd5b5289412efcbb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 11755cb1eb16..e69c6c9957a2 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -432,6 +433,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -3837,6 +3839,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.47.1 + diff --git a/patches/6.14/0004-ath10k.patch b/patches/6.14/0004-ath10k.patch new file mode 100644 index 0000000000..e1e6253a8b --- /dev/null +++ b/patches/6.14/0004-ath10k.patch @@ -0,0 +1,120 @@ +From cc9a74a369def421de56b0581f6131c4cd15355d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index b3294287bce1..2936fdae823c 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.47.1 + diff --git a/patches/6.14/0005-ipts.patch b/patches/6.14/0005-ipts.patch new file mode 100644 index 0000000000..9118fbc16a --- /dev/null +++ b/patches/6.14/0005-ipts.patch @@ -0,0 +1,3251 @@ +From 3e89507b8f6c6d36e5bf587a74c65be5d9796ffd Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index c3a6657dcd4a..82eef2f4eb0a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6589635f8ba3..a1df48a434e2 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.47.1 + +From 1d6df5a556693e735cc78a603c29112a76ee883b Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index cc23cfcdeb2d..c010aebe6cc1 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -40,6 +40,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -2046,6 +2053,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2344,6 +2354,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4651,6 +4664,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4686,6 +4711,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.47.1 + +From e4e616d49f7a021b83cd0114f0642090e88a054f Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index f8a56d631242..38eb29e4cc31 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1386,12 +1386,14 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + + source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled + + source "drivers/hid/usbhid/Kconfig" + + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 496dab54c73a..02588e5d01eb 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -171,5 +171,7 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.47.1 + diff --git a/patches/6.14/0006-ithc.patch b/patches/6.14/0006-ithc.patch new file mode 100644 index 0000000000..3191f6384a --- /dev/null +++ b/patches/6.14/0006-ithc.patch @@ -0,0 +1,2783 @@ +From d07e07e448b9b1ac7102911263626b623f138a28 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 7a6d188e3bea..0179baee4596 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.47.1 + +From 280c63dff160b59d1cbac71a63dc7f16d335fec9 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 38eb29e4cc31..76ad7d9143c7 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1375,12 +1375,14 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled + + source "drivers/hid/usbhid/Kconfig" + + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 02588e5d01eb..1ea3d2e0d4e9 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,6 +173,8 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.47.1 + diff --git a/patches/6.14/0007-surface-sam-over-hid.patch b/patches/6.14/0007-surface-sam-over-hid.patch new file mode 100644 index 0000000000..a65acd8e4f --- /dev/null +++ b/patches/6.14/0007-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From 064893f3e33bd77cecece7ea4047b3a6e1147fe2 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index 14ae0cfc325e..6197c5252d2a 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.47.1 + +From f6714cb9a95aeec3379336df70e7cc8d9537f727 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.47.1 + diff --git a/patches/6.14/0008-surface-button.patch b/patches/6.14/0008-surface-button.patch new file mode 100644 index 0000000000..934e9156d2 --- /dev/null +++ b/patches/6.14/0008-surface-button.patch @@ -0,0 +1,149 @@ +From 9d06bf6cc92b13c9e4c4781484b82804c4150d80 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index 5c5d407fe965..4e1bfe90e730 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.47.1 + +From f870bb021693abb7ea617c323216c615151b62e1 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.47.1 + diff --git a/patches/6.14/0009-surface-typecover.patch b/patches/6.14/0009-surface-typecover.patch new file mode 100644 index 0000000000..7cc1b3eb95 --- /dev/null +++ b/patches/6.14/0009-surface-typecover.patch @@ -0,0 +1,575 @@ +From df8f9981df6f0a92100266397ded155314efc7e3 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 13171454f959..a83beefd25f3 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.47.1 + +From 3aa9fc5fd7faed0bd5948e80e6ef6173c32a83ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e936019d21fe..08fee06fb5fc 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -34,7 +34,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -168,6 +175,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -402,6 +412,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1751,6 +1771,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1774,6 +1857,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1812,8 +1898,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); +@@ -1822,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1873,6 +1963,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2299,6 +2390,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.47.1 + +From c88ebc0ed1f21ec7ad52aa4fb2c48226603d7596 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 08fee06fb5fc..f6664049f46d 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -414,6 +417,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1395,6 +1399,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1422,6 +1429,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1443,6 +1465,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1450,6 +1473,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1459,11 +1495,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1641,6 +1687,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1689,6 +1771,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1771,30 +1860,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1803,8 +1868,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1941,13 +2007,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1956,12 +2033,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); +-- +2.47.1 + diff --git a/patches/6.14/0010-surface-shutdown.patch b/patches/6.14/0010-surface-shutdown.patch new file mode 100644 index 0000000000..d761cea88b --- /dev/null +++ b/patches/6.14/0010-surface-shutdown.patch @@ -0,0 +1,104 @@ +From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 35270172c833..529779994ef6 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 8103bc24a54e..e8fa8d810925 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6301,3 +6301,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 4e77c4230c0a..a4b0e6ef6cfe 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -477,13 +477,14 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ + unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + + spinlock_t pcie_cap_lock; /* Protects RMW ops in capability accessors */ + u32 saved_config_space[16]; /* Config space saved at suspend time */ + struct hlist_head saved_cap_space; + struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ + struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ + +-- +2.47.1 + diff --git a/patches/6.14/0011-surface-gpe.patch b/patches/6.14/0011-surface-gpe.patch new file mode 100644 index 0000000000..cb83acb03c --- /dev/null +++ b/patches/6.14/0011-surface-gpe.patch @@ -0,0 +1,51 @@ +From 8120dc21068acfe547e9c6d1cced417e5931c7ad Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index 62fd4004db31..103fc4468262 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.47.1 + diff --git a/patches/6.14/0013-amd-gpio.patch b/patches/6.14/0013-amd-gpio.patch new file mode 100644 index 0000000000..93c8956a23 --- /dev/null +++ b/patches/6.14/0013-amd-gpio.patch @@ -0,0 +1,109 @@ +From 28b8120e4f9b02ec49ccedd036557552a1aee5dc Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 4efecac49863..88377bb0d137 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.47.1 + +From 1b801d759aced457e5508cf931fa849400233b92 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 88377bb0d137..c58f26918b17 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.47.1 + diff --git a/patches/6.14/0014-rtc.patch b/patches/6.14/0014-rtc.patch new file mode 100644 index 0000000000..784921d06d --- /dev/null +++ b/patches/6.14/0014-rtc.patch @@ -0,0 +1,110 @@ +From 0a6b868f61d7564bc898ac30c84fbf3c34fb7368 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index b831cb8e53dc..78bd0f926505 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.47.1 + From e962ef827556653cabfb29fbd511a68b6e06375b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:24:42 +0200 Subject: [PATCH 094/236] Add config fragment for v6.14 --- configs/surface-6.14.config | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 configs/surface-6.14.config diff --git a/configs/surface-6.14.config b/configs/surface-6.14.config new file mode 100644 index 0000000000..d58d539727 --- /dev/null +++ b/configs/surface-6.14.config @@ -0,0 +1,83 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +CONFIG_RTC_DRV_SURFACE=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m From 2045881bdda1775bda8c3c90b009eab39f85194c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:27:55 +0200 Subject: [PATCH 095/236] Update v6.13 patches Changes: - Add basic SAM support for Surface Laptop 7 (Intel) - Rebase onto v6.13.11 Links: - kernel: https://github.com/linux-surface/kernel/commit/7cbc63f6b6c283aff7d337169751b0157d9cdd5b --- patches/6.13-fedora/0001-secureboot.patch | 8 +-- patches/6.13-fedora/0002-surface3.patch | 8 +-- patches/6.13-fedora/0003-mwifiex.patch | 16 ++--- patches/6.13-fedora/0004-ath10k.patch | 4 +- patches/6.13-fedora/0005-ipts.patch | 24 +++---- patches/6.13-fedora/0006-ithc.patch | 16 ++--- patches/6.13-fedora/0007-surface-sam.patch | 72 ++++++++----------- .../0008-surface-sam-over-hid.patch | 8 +-- patches/6.13-fedora/0009-surface-button.patch | 8 +-- .../6.13-fedora/0010-surface-typecover.patch | 14 ++-- .../6.13-fedora/0011-surface-shutdown.patch | 4 +- patches/6.13-fedora/0012-surface-gpe.patch | 4 +- patches/6.13-fedora/0013-cameras.patch | 50 ++++++------- patches/6.13-fedora/0014-amd-gpio.patch | 8 +-- patches/6.13-fedora/0015-rtc.patch | 4 +- patches/6.13/0001-secureboot.patch | 8 +-- patches/6.13/0002-surface3.patch | 8 +-- patches/6.13/0003-mwifiex.patch | 16 ++--- patches/6.13/0004-ath10k.patch | 4 +- patches/6.13/0005-ipts.patch | 24 +++---- patches/6.13/0006-ithc.patch | 16 ++--- patches/6.13/0007-surface-sam.patch | 72 ++++++++----------- patches/6.13/0008-surface-sam-over-hid.patch | 8 +-- patches/6.13/0009-surface-button.patch | 8 +-- patches/6.13/0010-surface-typecover.patch | 14 ++-- patches/6.13/0011-surface-shutdown.patch | 4 +- patches/6.13/0012-surface-gpe.patch | 4 +- patches/6.13/0013-cameras.patch | 50 ++++++------- patches/6.13/0014-amd-gpio.patch | 8 +-- patches/6.13/0015-rtc.patch | 4 +- 30 files changed, 236 insertions(+), 260 deletions(-) diff --git a/patches/6.13-fedora/0001-secureboot.patch b/patches/6.13-fedora/0001-secureboot.patch index cdc2745e60..c77b88a14e 100644 --- a/patches/6.13-fedora/0001-secureboot.patch +++ b/patches/6.13-fedora/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 94ade6781f154dfd06900517a4c18d20aad64c70 Mon Sep 17 00:00:00 2001 +From 7c9810fb3e614eba177052a3d4ed949de0c1a75e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.48.1 +2.49.0 -From 2bb6335216913bc247e2bc41f1ea2ff0a8981a4a Mon Sep 17 00:00:00 2001 +From 6ff310318f3a73e852625038b146dabe81501c34 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -108,5 +108,5 @@ index 10a01af63a80..e53e4a86e4cc 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0002-surface3.patch b/patches/6.13-fedora/0002-surface3.patch index a87871a25a..eb7cff72c4 100644 --- a/patches/6.13-fedora/0002-surface3.patch +++ b/patches/6.13-fedora/0002-surface3.patch @@ -1,4 +1,4 @@ -From 5e29598180e78ed9adbe88731ce2bbc9affb0ccc Mon Sep 17 00:00:00 2001 +From 481ba7958a7d0ae882d6a4ccbf47fa326acde51c Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,9 +97,9 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.48.1 +2.49.0 -From cd79bb7fed2cd0269d368cc4dea3194564262883 Mon Sep 17 00:00:00 2001 +From 2e5a1e90796ecbf74d851f179aeebd327da00f07 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -230,5 +230,5 @@ index 6074b7730e86..6aa3e1d6f160 100644 } -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0003-mwifiex.patch b/patches/6.13-fedora/0003-mwifiex.patch index bc0e6225d1..8f2988bf82 100644 --- a/patches/6.13-fedora/0003-mwifiex.patch +++ b/patches/6.13-fedora/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From c428669fce7eca5a597c0e7b0072e930f4895819 Mon Sep 17 00:00:00 2001 +From c4e6fa29a9f4a4a09a618574a8ecf7efa1e051fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.48.1 +2.49.0 -From 72f5a2ee698b9d344ea097930f2a0b7b617951d7 Mon Sep 17 00:00:00 2001 +From 1b3a3a96870f12d3d7001335039530e93b8bac36 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.48.1 +2.49.0 -From 964b1e54a083db2d78ba2352f706d297ed8b13c4 Mon Sep 17 00:00:00 2001 +From 517f11111b957f8e90dc9488a6bad4faf0fcec88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 72e85673b709..110c983dfd53 100644 +index 75dbe07e07e2..fd0f1aa5eaa9 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 72e85673b709..110c983dfd53 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3869,6 +3871,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3870,6 +3872,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 72e85673b709..110c983dfd53 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0004-ath10k.patch b/patches/6.13-fedora/0004-ath10k.patch index 5af6e07db4..67a4c54358 100644 --- a/patches/6.13-fedora/0004-ath10k.patch +++ b/patches/6.13-fedora/0004-ath10k.patch @@ -1,4 +1,4 @@ -From d8bf22111250427ec82a7918528346c714d39e24 Mon Sep 17 00:00:00 2001 +From 139fca7bcfd8aaa876636ff7c50f319028027073 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index b3294287bce1..2936fdae823c 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0005-ipts.patch b/patches/6.13-fedora/0005-ipts.patch index 6aa6b4c099..0529507211 100644 --- a/patches/6.13-fedora/0005-ipts.patch +++ b/patches/6.13-fedora/0005-ipts.patch @@ -1,4 +1,4 @@ -From 6b36fb0eff720194a680dd6d66fee5c47acff46c Mon Sep 17 00:00:00 2001 +From a7b5a85b385d7beabbb4f01f8bd2bcfcfcdffb4e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index c3a6657dcd4a..82eef2f4eb0a 100644 +index a5f88ec97df7..e379dc2373b5 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index c3a6657dcd4a..82eef2f4eb0a 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 6589635f8ba3..a1df48a434e2 100644 +index d6ff9d82ae94..a1b714505f43 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.48.1 +2.49.0 -From 468c032c6956af12d83aa0c7d86e2fd1a47221f3 Mon Sep 17 00:00:00 2001 +From 139a811cea8c408bc37e58b26cd593853f3efa64 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -142,9 +142,9 @@ index 9ab5371c3538..1839a831a89f 100644 { if (risky_device(dev)) -- -2.48.1 +2.49.0 -From 3e0542848e2fc70847d83533e082ab9cbc46d711 Mon Sep 17 00:00:00 2001 +From 7e49c5f2dce59ad34df0a3a9d01d17bf2e30771f Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,10 +211,10 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index c57927529f8a..9aabcf4241c6 100644 +index b7e010c384ba..d36a55e58598 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1388,4 +1388,6 @@ source "drivers/hid/surface-hid/Kconfig" +@@ -1389,4 +1389,6 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/intel-thc-hid/Kconfig" @@ -222,10 +222,10 @@ index c57927529f8a..9aabcf4241c6 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 482b096eea28..2024681e72fb 100644 +index 0abfe51704a0..c86c9e80d225 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -173,3 +173,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ +@@ -172,3 +172,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ @@ -3237,5 +3237,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0006-ithc.patch b/patches/6.13-fedora/0006-ithc.patch index 231b2449e9..a4ca4ecbac 100644 --- a/patches/6.13-fedora/0006-ithc.patch +++ b/patches/6.13-fedora/0006-ithc.patch @@ -1,4 +1,4 @@ -From acb1100081559166a23b76a7151b958f0b43a740 Mon Sep 17 00:00:00 2001 +From 7dbcb0c475dacbbaec0ae72c3c74c8d3087109e6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index 466c1412dd45..565686813588 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.48.1 +2.49.0 -From 860404c8e0c0789f6dcc29cb82ff913a9276bd63 Mon Sep 17 00:00:00 2001 +From 9af03ac81e7098a54bf697e915d5a4163fba65bd Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,10 +86,10 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 9aabcf4241c6..f7ee006bff6d 100644 +index d36a55e58598..ff709b2cb72b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1390,4 +1390,6 @@ source "drivers/hid/intel-thc-hid/Kconfig" +@@ -1391,4 +1391,6 @@ source "drivers/hid/intel-thc-hid/Kconfig" source "drivers/hid/ipts/Kconfig" @@ -97,10 +97,10 @@ index 9aabcf4241c6..f7ee006bff6d 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 2024681e72fb..f5dcee37fe8a 100644 +index c86c9e80d225..046eb5fd8017 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -175,3 +175,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ +@@ -174,3 +174,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ obj-$(CONFIG_HID_IPTS) += ipts/ @@ -2767,5 +2767,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0007-surface-sam.patch b/patches/6.13-fedora/0007-surface-sam.patch index ed3c409fd7..f990e2d047 100644 --- a/patches/6.13-fedora/0007-surface-sam.patch +++ b/patches/6.13-fedora/0007-surface-sam.patch @@ -1,44 +1,4 @@ -From 1c5d9203a4fc782d1934187ccb6e454a6a110b9c Mon Sep 17 00:00:00 2001 -From: Lukas -Date: Sat, 8 Mar 2025 22:00:46 +0100 -Subject: [PATCH] platform/surface: aggregator_registry: Add support for - Surface Pro 11 - -Add Support for the Surface Pro 11. As the SAM clients are equivalent to -the Surface Pro 9, reuse its nodes. - -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index d4f32ad66530..08b4ef382fab 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -371,7 +371,7 @@ static const struct software_node *ssam_node_group_sp8[] = { - NULL, - }; - --/* Devices for Surface Pro 9 (Intel/x86) and 10 */ -+/* Devices for Surface Pro 9 (Intel/x86), 10 and 11 */ - static const struct software_node *ssam_node_group_sp9[] = { - &ssam_node_root, - &ssam_node_hub_kip, -@@ -430,6 +430,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { - /* Surface Pro 10 */ - { "MSHW0510", (unsigned long)ssam_node_group_sp9 }, - -+ /* Surface Pro 11 */ -+ { "MSHW0583", (unsigned long)ssam_node_group_sp9 }, -+ - /* Surface Book 2 */ - { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, - --- -2.48.1 - -From 6250d3bbd6a70dbbbb44856314facc9649f3784c Mon Sep 17 00:00:00 2001 +From a0fe196b68e1a7fc549f760b547aee3ca1dea10c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -219,5 +179,33 @@ index 000000000000..f6c17c4e98d5 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.48.1 +2.49.0 + +From 92d3a8b58b89ed089e53517d1774f5670f7af4ab Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 20 Apr 2025 01:05:14 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 + (ACPI) + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index a594d5fcfcfd..07b03aa4fa7f 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Laptop 6 */ + { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + ++ /* Surface Laptop 7 */ ++ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.49.0 diff --git a/patches/6.13-fedora/0008-surface-sam-over-hid.patch b/patches/6.13-fedora/0008-surface-sam-over-hid.patch index 491b74de2e..96dbee9a2a 100644 --- a/patches/6.13-fedora/0008-surface-sam-over-hid.patch +++ b/patches/6.13-fedora/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 801aead8a7443382f7c4c5ffea712cfda1ad102c Mon Sep 17 00:00:00 2001 +From f98ac023ab5b5b71124de89e18fe82bc425de93e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index d2499f302b50..77ce5ec3dd9e 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.48.1 +2.49.0 -From f849b992c262e89b05810602390e41da0e9f185d Mon Sep 17 00:00:00 2001 +From 9bdc6328ce24cd5f739761d2b0c4db257e7378fb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0009-surface-button.patch b/patches/6.13-fedora/0009-surface-button.patch index 8429495b40..e18120c2f1 100644 --- a/patches/6.13-fedora/0009-surface-button.patch +++ b/patches/6.13-fedora/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 5259336f8461ac0b8d0e625b614d61274e70be09 Mon Sep 17 00:00:00 2001 +From 5f9bc92e987765bd9439c5dd720dad422db3e5c9 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index b8cad415c62c..43b5d56383e3 100644 /* -- -2.48.1 +2.49.0 -From 50d8655cc723db3b6462bfbc4c711694da923ae6 Mon Sep 17 00:00:00 2001 +From 7ed80ee3276381056a25b279e75996aec50d9be0 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0010-surface-typecover.patch b/patches/6.13-fedora/0010-surface-typecover.patch index f22e4de76f..4082f72ce8 100644 --- a/patches/6.13-fedora/0010-surface-typecover.patch +++ b/patches/6.13-fedora/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 0f982a17fd6d3c96be3c3dd066a6250211666984 Mon Sep 17 00:00:00 2001 +From 3199aa309ef61de73c2ec3497f749317b5f9a373 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 027479179f09..ee5a6bf5452d 100644 +index 6926bd639ec6..b08e3d206c31 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index 027479179f09..ee5a6bf5452d 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.48.1 +2.49.0 -From 00663433f93be502d076cb5d66d0ec957ddeff29 Mon Sep 17 00:00:00 2001 +From 48079de103d77441dc589fc95393279dfd37befa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -272,9 +272,9 @@ index e50887a6d22c..4ce18f21a141 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.48.1 +2.49.0 -From 3d6dc5f4bc862a62c0a1316e066d9d07ca17c4e1 Mon Sep 17 00:00:00 2001 +From bfb737e0a469bc8031f2e6d6007837e569b6fa3f Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -571,5 +571,5 @@ index 4ce18f21a141..f5e4d52bd2eb 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0011-surface-shutdown.patch b/patches/6.13-fedora/0011-surface-shutdown.patch index 575b56161a..eb64d474a9 100644 --- a/patches/6.13-fedora/0011-surface-shutdown.patch +++ b/patches/6.13-fedora/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 222392358de9542132abcb173bfdc1d8a47deee3 Mon Sep 17 00:00:00 2001 +From ae923cbf9f936baf98fd05461fae2f184ab2eafa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -93,5 +93,5 @@ index f05903dd7695..d1e38fdaf8bb 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0012-surface-gpe.patch b/patches/6.13-fedora/0012-surface-gpe.patch index b4a3183c28..cf2ce019ca 100644 --- a/patches/6.13-fedora/0012-surface-gpe.patch +++ b/patches/6.13-fedora/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From df5ea6881e7fd0d73be29469721377d5ecbc4bd7 Mon Sep 17 00:00:00 2001 +From 0660fd9f54beae759023eba1206bc335a0520456 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index b359413903b1..b4496db79f39 100644 .ident = "Surface Book 1", .matches = { -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0013-cameras.patch b/patches/6.13-fedora/0013-cameras.patch index 9bf6e1261f..c06d05b3ad 100644 --- a/patches/6.13-fedora/0013-cameras.patch +++ b/patches/6.13-fedora/0013-cameras.patch @@ -1,4 +1,4 @@ -From 6675cd092b80f34b8697aa9012855e351eb704db Mon Sep 17 00:00:00 2001 +From c3ad75a88591c4fae17287d81ad262915b995a63 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index d6265ddc87ef..2a5fcdff4d69 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.48.1 +2.49.0 -From d225b017ed8cadd981353e1cf114cddf79444cfc Mon Sep 17 00:00:00 2001 +From 6cb288a1c01f510952bc52b2bfdfdc995f87df5a Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -182,9 +182,9 @@ index 1839a831a89f..ebd7aa6b9038 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.48.1 +2.49.0 -From 9c19e6347c9da54ab936be79799c010c06710aa4 Mon Sep 17 00:00:00 2001 +From 6ed7b1d776a5093ef202df1644aaf749d4c59e30 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 81ac4c691963..f453c9043042 100644 return 0; -- -2.48.1 +2.49.0 -From 46a21f6b29916e6e600eefb53c054bf684c34e49 Mon Sep 17 00:00:00 2001 +From afb5099a5ee3e5687f4950170338997e09c22d6d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -243,11 +243,11 @@ Patchset: cameras 1 file changed, 15 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 09fff213b091..ce641eb45de6 100644 +index a80c981caa34..68d0f07dda0c 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - const char *func, u32 polarity) +@@ -81,12 +81,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, unsigned long gpio_flags) { int ret; + const struct acpi_device_id ov7251_ids[] = { @@ -268,16 +268,16 @@ index 09fff213b091..ce641eb45de6 100644 + */ + if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { + func = "enable"; -+ polarity ^= GPIO_ACTIVE_LOW; ++ gpio_flags ^= GPIO_ACTIVE_LOW; + } + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, func, polarity); + agpio, func, gpio_flags); if (ret) -- -2.48.1 +2.49.0 -From 0a96da6ea51e6117da7bc09ec2b1a4825bf3f1d0 Mon Sep 17 00:00:00 2001 +From 9f64f577e063bc55f0792e86749fae2be3edeb7d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -314,9 +314,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.48.1 +2.49.0 -From 5be6985f9a839a162a69b8cd73345fb77ccceea2 Mon Sep 17 00:00:00 2001 +From d0da4f26a459eccb3dff3e85bf5d4d62b0610815 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -365,9 +365,9 @@ index f19c8adf2c61..923ed1b5ab8b 100644 if (ret < 0) goto out_cleanup; -- -2.48.1 +2.49.0 -From d625f41c3c85ffc29c9f11a6040324052edebc0a Mon Sep 17 00:00:00 2001 +From 435c11d00b0daa5b011dc401e38ab209f10bca75 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -406,9 +406,9 @@ index f453c9043042..b8ad6b413e8b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.48.1 +2.49.0 -From 26cea0a675dd2392b0fc23d9b1f9633e131e6b6c Mon Sep 17 00:00:00 2001 +From 8f5b49efb0cdf75553a1491e3620955581d369c2 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -447,9 +447,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.48.1 +2.49.0 -From 61c8e3ff365f40be6c82f7e0b9895a60159e2c94 Mon Sep 17 00:00:00 2001 +From 7ade024275c62ea257aa474632534b709d67fafa Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -698,9 +698,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.48.1 +2.49.0 -From 62551f0c278803ba20e5ecbfe600f49d675d0855 Mon Sep 17 00:00:00 2001 +From a912466b23ce74196341f724384b46957d3a78b2 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -730,5 +730,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0014-amd-gpio.patch b/patches/6.13-fedora/0014-amd-gpio.patch index 8b1a8b493a..caadf0232f 100644 --- a/patches/6.13-fedora/0014-amd-gpio.patch +++ b/patches/6.13-fedora/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 2b479b02392b0a54e6e8c816c43db4f324f7f3da Mon Sep 17 00:00:00 2001 +From f8321346a2cfef4e6fe50b643a81798a96cc8bf6 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 18485170d51b..66d1b9e8aa9d 100644 mp_config_acpi_legacy_irqs(); -- -2.48.1 +2.49.0 -From f92cb8388023fb303b14dfcfb65782834ab4b172 Mon Sep 17 00:00:00 2001 +From 932d58e876e827ce1d705056b0b13c16efdbf427 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 66d1b9e8aa9d..741e05190b41 100644 }; -- -2.48.1 +2.49.0 diff --git a/patches/6.13-fedora/0015-rtc.patch b/patches/6.13-fedora/0015-rtc.patch index 924e6ce16b..ecbb751b8a 100644 --- a/patches/6.13-fedora/0015-rtc.patch +++ b/patches/6.13-fedora/0015-rtc.patch @@ -1,4 +1,4 @@ -From b79ca491e86cc6bf4c60988f3dc9a332288340f1 Mon Sep 17 00:00:00 2001 +From 9ae940ef2a162d1175e19fe58451e3681d3cdeeb Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 825c2a8acea4..74612088ac5f 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0001-secureboot.patch b/patches/6.13/0001-secureboot.patch index 2001fa6210..32c1ff237d 100644 --- a/patches/6.13/0001-secureboot.patch +++ b/patches/6.13/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 4d009b53e8096425207fc6682b4678264ea70b8e Mon Sep 17 00:00:00 2001 +From 4b43dd2ed91c6e744808726ef85c4926a99bedf5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.48.1 +2.49.0 -From f8c846bc0fc48b8399ea88427df65e12bf0e44db Mon Sep 17 00:00:00 2001 +From 558331080b6d47dfe55d3a4394fbdf2a3175940b Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -108,5 +108,5 @@ index 10a01af63a80..e53e4a86e4cc 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0002-surface3.patch b/patches/6.13/0002-surface3.patch index 2a5ab67cef..8e65cf4323 100644 --- a/patches/6.13/0002-surface3.patch +++ b/patches/6.13/0002-surface3.patch @@ -1,4 +1,4 @@ -From 1c36e25e29f59846a44c35a3bb204bfa0663860a Mon Sep 17 00:00:00 2001 +From 1861d3780461b6a1640979f316576342b1a9c990 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,9 +97,9 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.48.1 +2.49.0 -From b14f3b2d0baf0778bb4b1e69a692ae2b21987aec Mon Sep 17 00:00:00 2001 +From d1425f39cb72c625b785ae50b563543f9cdf384b Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -230,5 +230,5 @@ index 6074b7730e86..6aa3e1d6f160 100644 } -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0003-mwifiex.patch b/patches/6.13/0003-mwifiex.patch index f901b0ebd2..1ba129b6a0 100644 --- a/patches/6.13/0003-mwifiex.patch +++ b/patches/6.13/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 29f233ddc5afdf6f36d0049d7ee271445158dbdc Mon Sep 17 00:00:00 2001 +From 9c9103776669669ae724ca844f9ea1c24a3858dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.48.1 +2.49.0 -From 98097d6f99d54495af0feee4345ed6d92d547e60 Mon Sep 17 00:00:00 2001 +From de88988bb0d5cbe32fabac2241c84c394d988c3d Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.48.1 +2.49.0 -From 8d3ba13b4229f989721b335198b56d33ee508552 Mon Sep 17 00:00:00 2001 +From 4abcf78a128e215d638f9718acf11858cd5f278a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 72e85673b709..110c983dfd53 100644 +index 75dbe07e07e2..fd0f1aa5eaa9 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 72e85673b709..110c983dfd53 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3869,6 +3871,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3870,6 +3872,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 72e85673b709..110c983dfd53 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0004-ath10k.patch b/patches/6.13/0004-ath10k.patch index ac7c63cbbe..d659441c60 100644 --- a/patches/6.13/0004-ath10k.patch +++ b/patches/6.13/0004-ath10k.patch @@ -1,4 +1,4 @@ -From fadbf4e719d243db53a4e644515dfd8f2b12198d Mon Sep 17 00:00:00 2001 +From c859f592a5dfe3f04fecbf2be6c6fd470759008e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index b3294287bce1..2936fdae823c 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0005-ipts.patch b/patches/6.13/0005-ipts.patch index 24743210b6..31b55fbb8c 100644 --- a/patches/6.13/0005-ipts.patch +++ b/patches/6.13/0005-ipts.patch @@ -1,4 +1,4 @@ -From fc8b194519d2c8fd64a374ad5ca03b8d5cd0cf34 Mon Sep 17 00:00:00 2001 +From 9afe48759efd50b5a28f2e01118464a72f1cfb70 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index c3a6657dcd4a..82eef2f4eb0a 100644 +index a5f88ec97df7..e379dc2373b5 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index c3a6657dcd4a..82eef2f4eb0a 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 6589635f8ba3..a1df48a434e2 100644 +index d6ff9d82ae94..a1b714505f43 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.48.1 +2.49.0 -From 75bd5dd5e9bb6724c24a8574ef33462be36574b5 Mon Sep 17 00:00:00 2001 +From 0e2a5e55b467f538bdf2ec6c91c4b7aa36fc083f Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -142,9 +142,9 @@ index 9ab5371c3538..1839a831a89f 100644 { if (risky_device(dev)) -- -2.48.1 +2.49.0 -From c1562dcece75359bcc519d9a034f30fbe2c61f14 Mon Sep 17 00:00:00 2001 +From bed448bd281fe2969f17049a5a2192d1e5374618 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,10 +211,10 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 4d2a89d65b65..ce8e61de72c7 100644 +index 363c860835d3..799aceeeea89 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1386,4 +1386,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" +@@ -1387,4 +1387,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" source "drivers/hid/surface-hid/Kconfig" @@ -222,10 +222,10 @@ index 4d2a89d65b65..ce8e61de72c7 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 24de45f3677d..c33ea76797a7 100644 +index 1f50a6ecadbb..b82016429b01 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -171,3 +171,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ +@@ -170,3 +170,5 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ @@ -3237,5 +3237,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0006-ithc.patch b/patches/6.13/0006-ithc.patch index b952ac6f0d..68553e49bc 100644 --- a/patches/6.13/0006-ithc.patch +++ b/patches/6.13/0006-ithc.patch @@ -1,4 +1,4 @@ -From 761d58754af7780fa1fbc39764a8b944478aefa7 Mon Sep 17 00:00:00 2001 +From bccd64f261b835edd1abfc24c2f6ec170fb54728 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index 466c1412dd45..565686813588 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.48.1 +2.49.0 -From 4a1179f85e091a21417cc81b5e3813dbcc996107 Mon Sep 17 00:00:00 2001 +From 4ad821daf98ea471e649a4c7e5be4c4ea140000b Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,10 +86,10 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index ce8e61de72c7..db6665977a32 100644 +index 799aceeeea89..8b09289cbe8a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1388,4 +1388,6 @@ source "drivers/hid/surface-hid/Kconfig" +@@ -1389,4 +1389,6 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/ipts/Kconfig" @@ -97,10 +97,10 @@ index ce8e61de72c7..db6665977a32 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index c33ea76797a7..6a89c1eb1b19 100644 +index b82016429b01..9ac9e13ad64c 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -173,3 +173,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ +@@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_HID_IPTS) += ipts/ @@ -2767,5 +2767,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0007-surface-sam.patch b/patches/6.13/0007-surface-sam.patch index 126878c15a..ccdd91ce36 100644 --- a/patches/6.13/0007-surface-sam.patch +++ b/patches/6.13/0007-surface-sam.patch @@ -1,44 +1,4 @@ -From f380056e3a34dd28350a41869034943fe78d0041 Mon Sep 17 00:00:00 2001 -From: Lukas -Date: Sat, 8 Mar 2025 22:00:46 +0100 -Subject: [PATCH] platform/surface: aggregator_registry: Add support for - Surface Pro 11 - -Add Support for the Surface Pro 11. As the SAM clients are equivalent to -the Surface Pro 9, reuse its nodes. - -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index d4f32ad66530..08b4ef382fab 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -371,7 +371,7 @@ static const struct software_node *ssam_node_group_sp8[] = { - NULL, - }; - --/* Devices for Surface Pro 9 (Intel/x86) and 10 */ -+/* Devices for Surface Pro 9 (Intel/x86), 10 and 11 */ - static const struct software_node *ssam_node_group_sp9[] = { - &ssam_node_root, - &ssam_node_hub_kip, -@@ -430,6 +430,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { - /* Surface Pro 10 */ - { "MSHW0510", (unsigned long)ssam_node_group_sp9 }, - -+ /* Surface Pro 11 */ -+ { "MSHW0583", (unsigned long)ssam_node_group_sp9 }, -+ - /* Surface Book 2 */ - { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, - --- -2.48.1 - -From 0fb14f0e1961e47fed10351be0793d44708ea3ad Mon Sep 17 00:00:00 2001 +From 743c35534434dc42eecd818a5d6d02f33032f2f7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -219,5 +179,33 @@ index 000000000000..f6c17c4e98d5 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.48.1 +2.49.0 + +From 47fccc8a7d20139c64577c160bc56eaf4bc2b953 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 20 Apr 2025 01:05:14 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 + (ACPI) + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index a594d5fcfcfd..07b03aa4fa7f 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Laptop 6 */ + { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + ++ /* Surface Laptop 7 */ ++ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.49.0 diff --git a/patches/6.13/0008-surface-sam-over-hid.patch b/patches/6.13/0008-surface-sam-over-hid.patch index 0b93b98564..96d111c477 100644 --- a/patches/6.13/0008-surface-sam-over-hid.patch +++ b/patches/6.13/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 28db0098e37b9ac1e261afd935c0e2c5e0ae3675 Mon Sep 17 00:00:00 2001 +From b31805e73ebae15726da67431317007ff11e91df Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index d2499f302b50..77ce5ec3dd9e 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.48.1 +2.49.0 -From d7f160e91330f15f3ce5806dd2eeda08b67683e6 Mon Sep 17 00:00:00 2001 +From 1383dcb9227a733f83c4a5f5fb266ade3eab27c8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0009-surface-button.patch b/patches/6.13/0009-surface-button.patch index 738b8732b8..2925fa5b82 100644 --- a/patches/6.13/0009-surface-button.patch +++ b/patches/6.13/0009-surface-button.patch @@ -1,4 +1,4 @@ -From cee06c726d818a4194f543f2fc99f69ed0a4a1ae Mon Sep 17 00:00:00 2001 +From 36744fee38cc8c3674e53a6a0521db8f84bf9ea1 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index b8cad415c62c..43b5d56383e3 100644 /* -- -2.48.1 +2.49.0 -From 2b8ce3b47ac424db0c4ac408c8122ccc494aa6ae Mon Sep 17 00:00:00 2001 +From 4bd976ecb12b42aa6b88924078a81cb42d8476a9 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0010-surface-typecover.patch b/patches/6.13/0010-surface-typecover.patch index b20bbc99c4..b86ff0fe1f 100644 --- a/patches/6.13/0010-surface-typecover.patch +++ b/patches/6.13/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From db94df7d6a30c9c4125013bd195ec41d4b04a379 Mon Sep 17 00:00:00 2001 +From 0409e9b3f615228d69485901cbcf251c830387a6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 027479179f09..ee5a6bf5452d 100644 +index 6926bd639ec6..b08e3d206c31 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index 027479179f09..ee5a6bf5452d 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.48.1 +2.49.0 -From d9c734fac1446ce245a98a5f592060cc20edb158 Mon Sep 17 00:00:00 2001 +From e240ca7b5b78037f573916c0e8c5fd7cffb07613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -272,9 +272,9 @@ index e50887a6d22c..4ce18f21a141 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.48.1 +2.49.0 -From 3e36c4a010af0175b6537a3e9b5f413e95105583 Mon Sep 17 00:00:00 2001 +From 09ee792ac8f01560084e2dad8eeaf7a4296dd850 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -571,5 +571,5 @@ index 4ce18f21a141..f5e4d52bd2eb 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0011-surface-shutdown.patch b/patches/6.13/0011-surface-shutdown.patch index 75db042d2f..47d83dd0a8 100644 --- a/patches/6.13/0011-surface-shutdown.patch +++ b/patches/6.13/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 4f1f9492b46f9eee2ce9f844e03722acefaf5089 Mon Sep 17 00:00:00 2001 +From a8fd28a346634ae41963cabaa22c249c66289cf6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -93,5 +93,5 @@ index f05903dd7695..d1e38fdaf8bb 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0012-surface-gpe.patch b/patches/6.13/0012-surface-gpe.patch index 0bec2f30c3..8328dc1e5d 100644 --- a/patches/6.13/0012-surface-gpe.patch +++ b/patches/6.13/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 424492cfdcccf128c28222d3bb3ba3f2ee05e3bd Mon Sep 17 00:00:00 2001 +From b7ce7965f7676337a02f806cc57d3dec2ebfc946 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index b359413903b1..b4496db79f39 100644 .ident = "Surface Book 1", .matches = { -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0013-cameras.patch b/patches/6.13/0013-cameras.patch index 2759b52546..0e8a6bff42 100644 --- a/patches/6.13/0013-cameras.patch +++ b/patches/6.13/0013-cameras.patch @@ -1,4 +1,4 @@ -From eff5ad8dccd6f5a16bccaf8dff294af5d429e8ad Mon Sep 17 00:00:00 2001 +From 027ae0a6a7af6791b208eab02e2903d7584ebe2f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index 74dcccdc6482..9b104f979abe 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.48.1 +2.49.0 -From fac80ec3139641ff4c494e7cd09d1648c7d8b2be Mon Sep 17 00:00:00 2001 +From 0df5096c55f417ba51e40b7e094b0e1fcfb9162f Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -182,9 +182,9 @@ index 1839a831a89f..ebd7aa6b9038 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.48.1 +2.49.0 -From f451c52ee26ece5d7019766e438a981ef6fe112c Mon Sep 17 00:00:00 2001 +From 11180426d5fe34b886682a7f2bbe8c061502c312 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 81ac4c691963..f453c9043042 100644 return 0; -- -2.48.1 +2.49.0 -From 04c30b68d29d35c3f1648919d191249b17f0b487 Mon Sep 17 00:00:00 2001 +From ab154f95bf4acaf98a5732c1efceeb9fa602f6c8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -243,11 +243,11 @@ Patchset: cameras 1 file changed, 15 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 09fff213b091..ce641eb45de6 100644 +index a80c981caa34..68d0f07dda0c 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - const char *func, u32 polarity) +@@ -81,12 +81,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, unsigned long gpio_flags) { int ret; + const struct acpi_device_id ov7251_ids[] = { @@ -268,16 +268,16 @@ index 09fff213b091..ce641eb45de6 100644 + */ + if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { + func = "enable"; -+ polarity ^= GPIO_ACTIVE_LOW; ++ gpio_flags ^= GPIO_ACTIVE_LOW; + } + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, func, polarity); + agpio, func, gpio_flags); if (ret) -- -2.48.1 +2.49.0 -From 45854373b2c865431add3e249e42090cb2412057 Mon Sep 17 00:00:00 2001 +From fe2b7efab5d7a89b0335daf29d72bb08b853c4d7 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -314,9 +314,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.48.1 +2.49.0 -From 7ae7dc83e5f08fafe78b6737b3d1ac6aa1c932a1 Mon Sep 17 00:00:00 2001 +From 56d08f849ecd0a3f0a801a4ac7e90d757528bf0c Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -365,9 +365,9 @@ index f19c8adf2c61..923ed1b5ab8b 100644 if (ret < 0) goto out_cleanup; -- -2.48.1 +2.49.0 -From d20654efdf6f940456501405e90e3ed096a64258 Mon Sep 17 00:00:00 2001 +From ba92bf1c2ccef5492906f74cc2be3f0f583032fa Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -406,9 +406,9 @@ index f453c9043042..b8ad6b413e8b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.48.1 +2.49.0 -From b46660642fed87df97974c1eb864bff34cb5f67c Mon Sep 17 00:00:00 2001 +From ac2829c3ae57463819f0cb28c48eae4147cfa12c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -447,9 +447,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.48.1 +2.49.0 -From 6771f76a6415179f12d68c24f599405f2ac939f1 Mon Sep 17 00:00:00 2001 +From 9f5b3820f1dd06d363ed73ef3997a63e218516bd Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -698,9 +698,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.48.1 +2.49.0 -From b00c21087ed9b70395b20328c11f2b43f4e07a99 Mon Sep 17 00:00:00 2001 +From 8766d0105b72c4c1f4fe9a36eb872cc2b3879c10 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -730,5 +730,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0014-amd-gpio.patch b/patches/6.13/0014-amd-gpio.patch index c6963a26c9..e6e2df08d3 100644 --- a/patches/6.13/0014-amd-gpio.patch +++ b/patches/6.13/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 04e4e3bd36af14f0d6d9eabbfd9b6090247e4eba Mon Sep 17 00:00:00 2001 +From 944244c44f80d631fff8058b0d9692dfd761b4f4 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 18485170d51b..66d1b9e8aa9d 100644 mp_config_acpi_legacy_irqs(); -- -2.48.1 +2.49.0 -From 438f8d54a08f27470165575040d3ee51cd943e52 Mon Sep 17 00:00:00 2001 +From 6c65b07967d9f713c87103cdfe80c1ded559f154 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 66d1b9e8aa9d..741e05190b41 100644 }; -- -2.48.1 +2.49.0 diff --git a/patches/6.13/0015-rtc.patch b/patches/6.13/0015-rtc.patch index 857f0eaeb9..ef1c5ebc27 100644 --- a/patches/6.13/0015-rtc.patch +++ b/patches/6.13/0015-rtc.patch @@ -1,4 +1,4 @@ -From 8b87bc2d8d00488493dc389fe768d6f9ad034fff Mon Sep 17 00:00:00 2001 +From 0600ea617b539cd7a04249b896ebdc28b43717b0 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 825c2a8acea4..74612088ac5f 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.48.1 +2.49.0 From dcb3ef91087a40df33177b5dc14a6bbf11b18181 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 02:33:43 +0200 Subject: [PATCH 096/236] Remove 6.14 RC patches --- patches/6.14-rc2/0001-secureboot.patch | 112 - patches/6.14-rc2/0002-surface3-oemb.patch | 101 - patches/6.14-rc2/0003-mwifiex.patch | 400 -- patches/6.14-rc2/0004-ath10k.patch | 120 - patches/6.14-rc2/0005-ipts.patch | 3245 ---------------- patches/6.14-rc2/0006-ithc.patch | 2773 -------------- .../6.14-rc2/0007-surface-sam-over-hid.patch | 308 -- patches/6.14-rc2/0008-surface-button.patch | 149 - patches/6.14-rc2/0009-surface-typecover.patch | 575 --- patches/6.14-rc2/0010-surface-shutdown.patch | 97 - patches/6.14-rc2/0011-surface-gpe.patch | 51 - patches/6.14-rc2/0012-cameras.patch | 734 ---- patches/6.14-rc2/0013-amd-gpio.patch | 109 - patches/6.14-rc2/0014-rtc.patch | 110 - patches/6.14-rc4/0001-secureboot.patch | 112 - patches/6.14-rc4/0002-surface3-oemb.patch | 101 - patches/6.14-rc4/0003-mwifiex.patch | 400 -- patches/6.14-rc4/0004-ath10k.patch | 120 - patches/6.14-rc4/0005-ipts.patch | 3250 ----------------- patches/6.14-rc4/0006-ithc.patch | 2779 -------------- .../6.14-rc4/0007-surface-sam-over-hid.patch | 308 -- patches/6.14-rc4/0008-surface-button.patch | 149 - patches/6.14-rc4/0009-surface-typecover.patch | 575 --- patches/6.14-rc4/0010-surface-shutdown.patch | 97 - patches/6.14-rc4/0011-surface-gpe.patch | 51 - patches/6.14-rc4/0012-cameras.patch | 734 ---- patches/6.14-rc4/0013-amd-gpio.patch | 109 - patches/6.14-rc4/0014-rtc.patch | 110 - 28 files changed, 17779 deletions(-) delete mode 100644 patches/6.14-rc2/0001-secureboot.patch delete mode 100644 patches/6.14-rc2/0002-surface3-oemb.patch delete mode 100644 patches/6.14-rc2/0003-mwifiex.patch delete mode 100644 patches/6.14-rc2/0004-ath10k.patch delete mode 100644 patches/6.14-rc2/0005-ipts.patch delete mode 100644 patches/6.14-rc2/0006-ithc.patch delete mode 100644 patches/6.14-rc2/0007-surface-sam-over-hid.patch delete mode 100644 patches/6.14-rc2/0008-surface-button.patch delete mode 100644 patches/6.14-rc2/0009-surface-typecover.patch delete mode 100644 patches/6.14-rc2/0010-surface-shutdown.patch delete mode 100644 patches/6.14-rc2/0011-surface-gpe.patch delete mode 100644 patches/6.14-rc2/0012-cameras.patch delete mode 100644 patches/6.14-rc2/0013-amd-gpio.patch delete mode 100644 patches/6.14-rc2/0014-rtc.patch delete mode 100644 patches/6.14-rc4/0001-secureboot.patch delete mode 100644 patches/6.14-rc4/0002-surface3-oemb.patch delete mode 100644 patches/6.14-rc4/0003-mwifiex.patch delete mode 100644 patches/6.14-rc4/0004-ath10k.patch delete mode 100644 patches/6.14-rc4/0005-ipts.patch delete mode 100644 patches/6.14-rc4/0006-ithc.patch delete mode 100644 patches/6.14-rc4/0007-surface-sam-over-hid.patch delete mode 100644 patches/6.14-rc4/0008-surface-button.patch delete mode 100644 patches/6.14-rc4/0009-surface-typecover.patch delete mode 100644 patches/6.14-rc4/0010-surface-shutdown.patch delete mode 100644 patches/6.14-rc4/0011-surface-gpe.patch delete mode 100644 patches/6.14-rc4/0012-cameras.patch delete mode 100644 patches/6.14-rc4/0013-amd-gpio.patch delete mode 100644 patches/6.14-rc4/0014-rtc.patch diff --git a/patches/6.14-rc2/0001-secureboot.patch b/patches/6.14-rc2/0001-secureboot.patch deleted file mode 100644 index addb86e813..0000000000 --- a/patches/6.14-rc2/0001-secureboot.patch +++ /dev/null @@ -1,112 +0,0 @@ -From bbcfb18eb05bd92e4501ca35bdfd558c849ddeda Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 9 Jun 2024 19:48:58 +0200 -Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag - unconditionally" - -This reverts commit 891f8890a4a3663da7056542757022870b499bc1. - -Revert because of compatibility issues of MS Surface devices and GRUB -with NX. In short, these devices get stuck on boot with NX advertised. -So to not advertise it, add the respective option back in. - -Signed-off-by: Maximilian Luz -Patchset: secureboot ---- - arch/x86/boot/header.S | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index b5c79f43359b..a1bbedd989e4 100644 ---- a/arch/x86/boot/header.S -+++ b/arch/x86/boot/header.S -@@ -111,7 +111,11 @@ extra_header_fields: - .long salign # SizeOfHeaders - .long 0 # CheckSum - .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) -+#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES - .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics -+#else -+ .word 0 # DllCharacteristics -+#endif - #ifdef CONFIG_X86_32 - .long 0 # SizeOfStackReserve - .long 0 # SizeOfStackCommit --- -2.47.1 - -From 9a796344897d077f1fc977ab026315c2cfcd3960 Mon Sep 17 00:00:00 2001 -From: "J. Eduardo" -Date: Sun, 25 Aug 2024 14:17:45 +0200 -Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter - -This allows the user to tell the kernel that they know better (namely, -they secured their swap properly), and that it can enable hibernation. - -Signed-off-by: Kelvie Wong -Link: https://github.com/linux-surface/kernel/pull/158 -Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee -Patchset: secureboot ---- - Documentation/admin-guide/kernel-parameters.txt | 5 +++++ - kernel/power/hibernate.c | 10 +++++++++- - 2 files changed, 14 insertions(+), 1 deletion(-) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index d401577b5a6a..5a812e0b740a 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3066,6 +3066,11 @@ - to extract confidential information from the kernel - are also disabled. - -+ lockdown_hibernate [HIBERNATION] -+ Enable hibernation even if lockdown is enabled. Enable this only if -+ your swap is encrypted and secured properly, as an attacker can -+ modify the kernel offline during hibernation. -+ - locktorture.acq_writer_lim= [KNL] - Set the time limit in jiffies for a lock - acquisition. Acquisitions exceeding this limit -diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index e35829d36039..6d54eb03b63d 100644 ---- a/kernel/power/hibernate.c -+++ b/kernel/power/hibernate.c -@@ -37,6 +37,7 @@ - #include "power.h" - - -+static int lockdown_hibernate; - static int nocompress; - static int noresume; - static int nohibernate; -@@ -92,7 +93,7 @@ void hibernate_release(void) - bool hibernation_available(void) - { - return nohibernate == 0 && -- !security_locked_down(LOCKDOWN_HIBERNATION) && -+ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && - !secretmem_active() && !cxl_mem_active(); - } - -@@ -1426,6 +1427,12 @@ static int __init nohibernate_setup(char *str) - return 1; - } - -+static int __init lockdown_hibernate_setup(char *str) -+{ -+ lockdown_hibernate = 1; -+ return 1; -+} -+ - static const char * const comp_alg_enabled[] = { - #if IS_ENABLED(CONFIG_CRYPTO_LZO) - COMPRESSION_ALGO_LZO, -@@ -1484,3 +1491,4 @@ __setup("hibernate=", hibernate_setup); - __setup("resumewait", resumewait_setup); - __setup("resumedelay=", resumedelay_setup); - __setup("nohibernate", nohibernate_setup); -+__setup("lockdown_hibernate", lockdown_hibernate_setup); --- -2.47.1 - diff --git a/patches/6.14-rc2/0002-surface3-oemb.patch b/patches/6.14-rc2/0002-surface3-oemb.patch deleted file mode 100644 index ab40dd606c..0000000000 --- a/patches/6.14-rc2/0002-surface3-oemb.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 2ce5cf2a597c9015c64ea9f386a396f97b8589c6 Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 18 Oct 2020 16:42:44 +0900 -Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI - table - -On some Surface 3, the DMI table gets corrupted for unknown reasons -and breaks existing DMI matching used for device-specific quirks. - -This commit adds the (broken) DMI data into dmi_system_id tables used -for quirks so that each driver can enable quirks even on the affected -systems. - -On affected systems, DMI data will look like this: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:OEMB - /sys/devices/virtual/dmi/id/board_vendor:OEMB - /sys/devices/virtual/dmi/id/chassis_vendor:OEMB - /sys/devices/virtual/dmi/id/product_name:OEMB - /sys/devices/virtual/dmi/id/sys_vendor:OEMB - -Expected: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:Surface 3 - /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/product_name:Surface 3 - /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation - -Signed-off-by: Tsuchiya Yuto -Patchset: surface3-oemb ---- - drivers/platform/surface/surface3-wmi.c | 7 +++++++ - sound/soc/codecs/rt5645.c | 9 +++++++++ - sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ - 3 files changed, 24 insertions(+) - -diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index c15ed7a12784..1ec8edb5aafa 100644 ---- a/drivers/platform/surface/surface3-wmi.c -+++ b/drivers/platform/surface/surface3-wmi.c -@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - #endif - { } - }; -diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 51187b1e0ed2..bfb83ce8d8f8 100644 ---- a/sound/soc/codecs/rt5645.c -+++ b/sound/soc/codecs/rt5645.c -@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { - }, - .driver_data = (void *)&intel_braswell_platform_data, - }, -+ { -+ .ident = "Microsoft Surface 3", -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ .driver_data = (void *)&intel_braswell_platform_data, -+ }, - { - /* - * Match for the GPDwin which unfortunately uses somewhat -diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0c28..0b930c91bccb 100644 ---- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .callback = cht_surface_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - { } - }; - --- -2.47.1 - diff --git a/patches/6.14-rc2/0003-mwifiex.patch b/patches/6.14-rc2/0003-mwifiex.patch deleted file mode 100644 index 523a943588..0000000000 --- a/patches/6.14-rc2/0003-mwifiex.patch +++ /dev/null @@ -1,400 +0,0 @@ -From ed54461506b98c1bc8ae8dc5f7385de1f900ed0b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Tue, 3 Nov 2020 13:28:04 +0100 -Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface - devices - -The most recent firmware of the 88W8897 card reports a hardcoded LTR -value to the system during initialization, probably as an (unsuccessful) -attempt of the developers to fix firmware crashes. This LTR value -prevents most of the Microsoft Surface devices from entering deep -powersaving states (either platform C-State 10 or S0ix state), because -the exit latency of that state would be higher than what the card can -tolerate. - -Turns out the card works just the same (including the firmware crashes) -no matter if that hardcoded LTR value is reported or not, so it's kind -of useless and only prevents us from saving power. - -To get rid of those hardcoded LTR reports, it's possible to reset the -PCI bridge device after initializing the cards firmware. I'm not exactly -sure why that works, maybe the power management subsystem of the PCH -resets its stored LTR values when doing a function level reset of the -bridge device. Doing the reset once after starting the wifi firmware -works very well, probably because the firmware only reports that LTR -value a single time during firmware startup. - -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 3 files changed, 31 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 5f997becdbaa..9a9929424513 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) - static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) - { - struct pcie_service_card *card = adapter->card; -+ struct pci_dev *pdev = card->dev; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; - -+ /* Trigger a function level reset of the PCI bridge device, this makes -+ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value -+ * that prevents the system from entering package C10 and S0ix powersaving -+ * states. -+ * We need to do it here because it must happen after firmware -+ * initialization and this function is called after that is done. -+ */ -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ pci_reset_function(parent_pdev); -+ - /* Write the RX ring read pointer in to reg->rx_rdptr */ - mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); - } -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5", -@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 6", -@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 1", -@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 2", -@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 1", -@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 2", -@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - {} - }; -@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "no quirks enabled\n"); - if (card->quirks & QUIRK_FW_RST_D3COLD) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); - } - - static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -4,6 +4,7 @@ - #include "pcie.h" - - #define QUIRK_FW_RST_D3COLD BIT(0) -+#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) - - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.47.1 - -From a93a869673e056cf2a2c46b9438edaca8f5e2645 Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 4 Oct 2020 00:11:49 +0900 -Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ - -Currently, mwifiex fw will crash after suspend on recent kernel series. -On Windows, it seems that the root port of wifi will never enter D3 state -(stay on D0 state). And on Linux, disabling the D3 state for the -bridge fixes fw crashing after suspend. - -This commit disables the D3 state of root port on driver initialization -and fixes fw crashing after suspend. - -Signed-off-by: Tsuchiya Yuto -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 3 files changed, 27 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 9a9929424513..2273e3029776 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) - { - struct pcie_service_card *card; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - int ret; - - pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", -@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - return -1; - } - -+ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing -+ * after suspend -+ */ -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ parent_pdev->bridge_d3 = false; -+ - return 0; - } - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5", -@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 6", -@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 1", -@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 2", -@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 1", -@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 2", -@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - {} - }; -@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); - if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) - dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ dev_info(&pdev->dev, -+ "quirk no_brigde_d3 enabled\n"); - } - - static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -5,6 +5,7 @@ - - #define QUIRK_FW_RST_D3COLD BIT(0) - #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) -+#define QUIRK_NO_BRIDGE_D3 BIT(2) - - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.47.1 - -From bcc616a02ed2a9e059d2e7a1dd5b5289412efcbb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 25 Mar 2021 11:33:02 +0100 -Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell - 88W8897 - -The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) -is used in a lot of Microsoft Surface devices, and all those devices -suffer from very low 2.4GHz wifi connection speeds while bluetooth is -enabled. The reason for that is that the default passive scanning -interval for Bluetooth Low Energy devices is quite high in Linux -(interval of 60 msec and scan window of 30 msec, see hci_core.c), and -the Marvell chip is known for its bad bt+wifi coexisting performance. - -So decrease that passive scan interval and make the scan window shorter -on this particular device to allow for spending more time transmitting -wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and -the new scan window is 6.25 msec (0xa * 0,625 msec). - -This change has a very large impact on the 2.4GHz wifi speeds and gets -it up to performance comparable with the Windows driver, which seems to -apply a similar quirk. - -The interval and window length were tested and found to work very well -with a lot of Bluetooth Low Energy devices, including the Surface Pen, a -Bluetooth Speaker and two modern Bluetooth headphones. All devices were -discovered immediately after turning them on. Even lower values were -also tested, but they introduced longer delays until devices get -discovered. - -Patchset: mwifiex ---- - drivers/bluetooth/btusb.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 11755cb1eb16..e69c6c9957a2 100644 ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; - #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) - #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) - #define BTUSB_ACTIONS_SEMI BIT(27) -+#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) - - static const struct usb_device_id btusb_table[] = { - /* Generic Bluetooth USB device */ -@@ -432,6 +433,7 @@ static const struct usb_device_id quirks_table[] = { - { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, - { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, - { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, -+ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, - - /* Intel Bluetooth devices */ - { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3837,6 +3839,19 @@ static int btusb_probe(struct usb_interface *intf, - if (id->driver_info & BTUSB_MARVELL) - hdev->set_bdaddr = btusb_set_bdaddr_marvell; - -+ /* The Marvell 88W8897 combined wifi and bluetooth card is known for -+ * very bad bt+wifi coexisting performance. -+ * -+ * Decrease the passive BT Low Energy scan interval a bit -+ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter -+ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly -+ * higher wifi throughput while passively scanning for BT LE devices. -+ */ -+ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { -+ hdev->le_scan_interval = 0x0190; -+ hdev->le_scan_window = 0x000a; -+ } -+ - if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && - (id->driver_info & BTUSB_MEDIATEK)) { - hdev->setup = btusb_mtk_setup; --- -2.47.1 - diff --git a/patches/6.14-rc2/0004-ath10k.patch b/patches/6.14-rc2/0004-ath10k.patch deleted file mode 100644 index e1e6253a8b..0000000000 --- a/patches/6.14-rc2/0004-ath10k.patch +++ /dev/null @@ -1,120 +0,0 @@ -From cc9a74a369def421de56b0581f6131c4cd15355d Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 27 Feb 2021 00:45:52 +0100 -Subject: [PATCH] ath10k: Add module parameters to override board files - -Some Surface devices, specifically the Surface Go and AMD version of the -Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better -with a different board file, as it seems that the firmeware included -upstream is buggy. - -As it is generally not a good idea to randomly overwrite files, let -alone doing so via packages, we add module parameters to override those -file names in the driver. This allows us to package/deploy the override -via a modprobe.d config. - -Signed-off-by: Maximilian Luz -Patchset: ath10k ---- - drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ - 1 file changed, 57 insertions(+) - -diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index b3294287bce1..2936fdae823c 100644 ---- a/drivers/net/wireless/ath/ath10k/core.c -+++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -40,6 +40,9 @@ static bool fw_diag_log; - /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ - unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; - -+static char *override_board = ""; -+static char *override_board2 = ""; -+ - unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | - BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); - -@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); - module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); - module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); - -+module_param(override_board, charp, 0644); -+module_param(override_board2, charp, 0644); -+ - MODULE_PARM_DESC(debug_mask, "Debugging mask"); - MODULE_PARM_DESC(uart_print, "Uart target debugging"); - MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); -@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, - MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); - MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); - -+MODULE_PARM_DESC(override_board, "Override for board.bin file"); -+MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); -+ - static const struct ath10k_hw_params ath10k_hw_params_list[] = { - { - .id = QCA988X_HW_2_0_VERSION, -@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) - return 0; - } - -+static const char *ath10k_override_board_fw_file(struct ath10k *ar, -+ const char *file) -+{ -+ if (strcmp(file, "board.bin") == 0) { -+ if (strcmp(override_board, "") == 0) -+ return file; -+ -+ if (strcmp(override_board, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); -+ return NULL; -+ } -+ -+ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", -+ override_board); -+ -+ return override_board; -+ } -+ -+ if (strcmp(file, "board-2.bin") == 0) { -+ if (strcmp(override_board2, "") == 0) -+ return file; -+ -+ if (strcmp(override_board2, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); -+ return NULL; -+ } -+ -+ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", -+ override_board2); -+ -+ return override_board2; -+ } -+ -+ return file; -+} -+ - static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - const char *dir, - const char *file) -@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - if (dir == NULL) - dir = "."; - -+ /* HACK: Override board.bin and board-2.bin files if specified. -+ * -+ * Some Surface devices perform better with a different board -+ * configuration. To this end, one would need to replace the board.bin -+ * file with the modified config and remove the board-2.bin file. -+ * Unfortunately, that's not a solution that we can easily package. So -+ * we add module options to perform these overrides here. -+ */ -+ file = ath10k_override_board_fw_file(ar, file); -+ if (!file) -+ return ERR_PTR(-ENOENT); -+ - if (ar->board_name) { - snprintf(filename, sizeof(filename), "%s/%s/%s", - dir, ar->board_name, file); --- -2.47.1 - diff --git a/patches/6.14-rc2/0005-ipts.patch b/patches/6.14-rc2/0005-ipts.patch deleted file mode 100644 index ea6999d915..0000000000 --- a/patches/6.14-rc2/0005-ipts.patch +++ /dev/null @@ -1,3245 +0,0 @@ -From 3e89507b8f6c6d36e5bf587a74c65be5d9796ffd Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Thu, 30 Jul 2020 13:21:53 +0200 -Subject: [PATCH] mei: me: Add Icelake device ID for iTouch - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/misc/mei/hw-me-regs.h | 1 + - drivers/misc/mei/pci-me.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index c3a6657dcd4a..82eef2f4eb0a 100644 ---- a/drivers/misc/mei/hw-me-regs.h -+++ b/drivers/misc/mei/hw-me-regs.h -@@ -92,6 +92,7 @@ - #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ - - #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ -+#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ - #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ - - #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ -diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 6589635f8ba3..a1df48a434e2 100644 ---- a/drivers/misc/mei/pci-me.c -+++ b/drivers/misc/mei/pci-me.c -@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { - {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, -+ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, --- -2.47.1 - -From 1d6df5a556693e735cc78a603c29112a76ee883b Mon Sep 17 00:00:00 2001 -From: Liban Hannan -Date: Tue, 12 Apr 2022 23:31:12 +0100 -Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS - -Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. -Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: - -DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr -0x104ea3000 [fault reason 0x06] PTE Read access is not set - -This is very similar to the bug described at: -https://bugs.launchpad.net/bugs/1958004 - -Fixed with the following patch which this patch basically copies: -https://launchpadlibrarian.net/586396847/43255ca.diff - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index cc23cfcdeb2d..c010aebe6cc1 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -40,6 +40,11 @@ - #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) - #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) - -+#define IS_IPTS(pdev) ( \ -+ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ -+ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ -+ ) -+ - #define IOAPIC_RANGE_START (0xfee00000) - #define IOAPIC_RANGE_END (0xfeefffff) - #define IOVA_START_ADDR (0x1000) -@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); - int intel_iommu_enabled = 0; - EXPORT_SYMBOL_GPL(intel_iommu_enabled); - -+static int dmar_map_ipts = 1; - static int intel_iommu_superpage = 1; - static int iommu_identity_mapping; - static int iommu_skip_te_disable; - static int disable_igfx_iommu; - - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPTS 16 - - const struct iommu_ops intel_iommu_ops; - static const struct iommu_dirty_ops intel_dirty_ops; -@@ -2046,6 +2053,9 @@ static int device_def_domain_type(struct device *dev) - - if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) - return IOMMU_DOMAIN_IDENTITY; -+ -+ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; - } - - return 0; -@@ -2344,6 +2354,9 @@ static int __init init_dmars(void) - iommu_set_root_entry(iommu); - } - -+ if (!dmar_map_ipts) -+ iommu_identity_mapping |= IDENTMAP_IPTS; -+ - check_tylersburg_isoch(); - - /* -@@ -4651,6 +4664,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - disable_igfx_iommu = 1; - } - -+static void quirk_iommu_ipts(struct pci_dev *dev) -+{ -+ if (!IS_IPTS(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; -+ -+ pci_info(dev, "Disabling IOMMU for IPTS\n"); -+ dmar_map_ipts = 0; -+} -+ - /* G4x/GM45 integrated gfx dmar support is totally busted. */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4686,6 +4711,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); - -+/* disable IPTS dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -+ - static void quirk_iommu_rwbf(struct pci_dev *dev) - { - if (risky_device(dev)) --- -2.47.1 - -From e4e616d49f7a021b83cd0114f0642090e88a054f Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Sun, 11 Dec 2022 12:00:59 +0100 -Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus - -Based on linux-surface/intel-precise-touch@8abe268 - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 2 + - drivers/hid/ipts/Kconfig | 14 + - drivers/hid/ipts/Makefile | 16 ++ - drivers/hid/ipts/cmd.c | 61 +++++ - drivers/hid/ipts/cmd.h | 60 ++++ - drivers/hid/ipts/context.h | 52 ++++ - drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ - drivers/hid/ipts/control.h | 126 +++++++++ - drivers/hid/ipts/desc.h | 80 ++++++ - drivers/hid/ipts/eds1.c | 104 +++++++ - drivers/hid/ipts/eds1.h | 35 +++ - drivers/hid/ipts/eds2.c | 145 ++++++++++ - drivers/hid/ipts/eds2.h | 35 +++ - drivers/hid/ipts/hid.c | 225 +++++++++++++++ - drivers/hid/ipts/hid.h | 24 ++ - drivers/hid/ipts/main.c | 126 +++++++++ - drivers/hid/ipts/mei.c | 188 +++++++++++++ - drivers/hid/ipts/mei.h | 66 +++++ - drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ - drivers/hid/ipts/receiver.h | 16 ++ - drivers/hid/ipts/resources.c | 131 +++++++++ - drivers/hid/ipts/resources.h | 41 +++ - drivers/hid/ipts/spec-data.h | 100 +++++++ - drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ - drivers/hid/ipts/spec-hid.h | 34 +++ - drivers/hid/ipts/thread.c | 84 ++++++ - drivers/hid/ipts/thread.h | 59 ++++ - 28 files changed, 2853 insertions(+) - create mode 100644 drivers/hid/ipts/Kconfig - create mode 100644 drivers/hid/ipts/Makefile - create mode 100644 drivers/hid/ipts/cmd.c - create mode 100644 drivers/hid/ipts/cmd.h - create mode 100644 drivers/hid/ipts/context.h - create mode 100644 drivers/hid/ipts/control.c - create mode 100644 drivers/hid/ipts/control.h - create mode 100644 drivers/hid/ipts/desc.h - create mode 100644 drivers/hid/ipts/eds1.c - create mode 100644 drivers/hid/ipts/eds1.h - create mode 100644 drivers/hid/ipts/eds2.c - create mode 100644 drivers/hid/ipts/eds2.h - create mode 100644 drivers/hid/ipts/hid.c - create mode 100644 drivers/hid/ipts/hid.h - create mode 100644 drivers/hid/ipts/main.c - create mode 100644 drivers/hid/ipts/mei.c - create mode 100644 drivers/hid/ipts/mei.h - create mode 100644 drivers/hid/ipts/receiver.c - create mode 100644 drivers/hid/ipts/receiver.h - create mode 100644 drivers/hid/ipts/resources.c - create mode 100644 drivers/hid/ipts/resources.h - create mode 100644 drivers/hid/ipts/spec-data.h - create mode 100644 drivers/hid/ipts/spec-device.h - create mode 100644 drivers/hid/ipts/spec-hid.h - create mode 100644 drivers/hid/ipts/thread.c - create mode 100644 drivers/hid/ipts/thread.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index f8a56d631242..38eb29e4cc31 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1386,6 +1386,8 @@ source "drivers/hid/amd-sfh-hid/Kconfig" - - source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/intel-thc-hid/Kconfig" - -+source "drivers/hid/ipts/Kconfig" -+ - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 496dab54c73a..02588e5d01eb 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -171,5 +171,7 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ - obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - - obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ -+ -+obj-$(CONFIG_HID_IPTS) += ipts/ -diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig -new file mode 100644 -index 000000000000..297401bd388d ---- /dev/null -+++ b/drivers/hid/ipts/Kconfig -@@ -0,0 +1,14 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+ -+config HID_IPTS -+ tristate "Intel Precise Touch & Stylus" -+ depends on INTEL_MEI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Precise Touch & Stylus (IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ipts. -diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile -new file mode 100644 -index 000000000000..883896f68e6a ---- /dev/null -+++ b/drivers/hid/ipts/Makefile -@@ -0,0 +1,16 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+# -+# Makefile for the IPTS touchscreen driver -+# -+ -+obj-$(CONFIG_HID_IPTS) += ipts.o -+ipts-objs := cmd.o -+ipts-objs += control.o -+ipts-objs += eds1.o -+ipts-objs += eds2.o -+ipts-objs += hid.o -+ipts-objs += main.o -+ipts-objs += mei.o -+ipts-objs += receiver.o -+ipts-objs += resources.o -+ipts-objs += thread.o -diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c -new file mode 100644 -index 000000000000..63a4934bbc5f ---- /dev/null -+++ b/drivers/hid/ipts/cmd.c -@@ -0,0 +1,61 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "mei.h" -+#include "spec-device.h" -+ -+int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp, u64 timeout) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!rsp) -+ return -EFAULT; -+ -+ /* -+ * In a response, the command code will have the most significant bit flipped to 1. -+ * If code is passed to ipts_mei_recv as is, no messages will be received. -+ */ -+ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); -+ if (ret < 0) -+ return ret; -+ -+ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); -+ -+ /* -+ * Some devices will always return this error. -+ * It is allowed to ignore it and to try continuing. -+ */ -+ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) -+ rsp->status = IPTS_STATUS_SUCCESS; -+ -+ return 0; -+} -+ -+int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) -+{ -+ struct ipts_command cmd = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.cmd = code; -+ -+ if (data && size > 0) -+ memcpy(cmd.payload, data, size); -+ -+ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); -+ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); -+} -diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h -new file mode 100644 -index 000000000000..2b4079075b64 ---- /dev/null -+++ b/drivers/hid/ipts/cmd.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CMD_H -+#define IPTS_CMD_H -+ -+#include -+ -+#include "context.h" -+#include "spec-device.h" -+ -+/* -+ * The default timeout for receiving responses -+ */ -+#define IPTS_CMD_DEFAULT_TIMEOUT 1000 -+ -+/** -+ * ipts_cmd_recv_timeout() - Receives a response to a command. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command / response. -+ * @rsp: The address that the received response will be copied to. -+ * @timeout: How many milliseconds the function will wait at most. -+ * -+ * A negative timeout means to wait forever. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp, u64 timeout); -+ -+/** -+ * ipts_cmd_recv() - Receives a response to a command. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command / response. -+ * @rsp: The address that the received response will be copied to. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp) -+{ -+ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); -+} -+ -+/** -+ * ipts_cmd_send() - Executes a command on the device. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command to execute. -+ * @data: The payload containing parameters for the command. -+ * @size: The size of the payload. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); -+ -+#endif /* IPTS_CMD_H */ -diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h -new file mode 100644 -index 000000000000..ba33259f1f7c ---- /dev/null -+++ b/drivers/hid/ipts/context.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CONTEXT_H -+#define IPTS_CONTEXT_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mei.h" -+#include "resources.h" -+#include "spec-device.h" -+#include "thread.h" -+ -+struct ipts_context { -+ struct device *dev; -+ struct ipts_mei mei; -+ -+ enum ipts_mode mode; -+ -+ /* -+ * Prevents concurrent GET_FEATURE reports. -+ */ -+ struct mutex feature_lock; -+ struct completion feature_event; -+ -+ /* -+ * These are not inside of struct ipts_resources -+ * because they don't own the memory they point to. -+ */ -+ struct ipts_buffer feature_report; -+ struct ipts_buffer descriptor; -+ -+ bool hid_active; -+ struct hid_device *hid; -+ -+ struct ipts_device_info info; -+ struct ipts_resources resources; -+ -+ struct ipts_thread receiver_loop; -+}; -+ -+#endif /* IPTS_CONTEXT_H */ -diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c -new file mode 100644 -index 000000000000..5360842d260b ---- /dev/null -+++ b/drivers/hid/ipts/control.c -@@ -0,0 +1,486 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "hid.h" -+#include "receiver.h" -+#include "resources.h" -+#include "spec-data.h" -+#include "spec-device.h" -+ -+static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!info) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ memcpy(info, rsp.payload, sizeof(*info)); -+ return 0; -+} -+ -+static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ struct ipts_set_mode cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.mode = mode; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) -+{ -+ int i = 0; -+ int ret = 0; -+ struct ipts_mem_window cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); -+ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); -+ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); -+ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); -+ } -+ -+ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); -+ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); -+ -+ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); -+ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); -+ -+ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); -+ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); -+ -+ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; -+ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+static int ipts_control_get_descriptor(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_data_header *header = NULL; -+ struct ipts_get_descriptor cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->resources.descriptor.address) -+ return -EFAULT; -+ -+ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); -+ -+ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); -+ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); -+ cmd.magic = 8; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ header = (struct ipts_data_header *)ipts->resources.descriptor.address; -+ -+ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { -+ ipts->descriptor.address = &header->data[8]; -+ ipts->descriptor.size = header->size - 8; -+ -+ return 0; -+ } -+ -+ return -ENODATA; -+} -+ -+int ipts_control_request_flush(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_quiesce_io cmd = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); -+ if (ret) -+ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_control_wait_flush(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status == IPTS_STATUS_TIMEOUT) -+ return -EAGAIN; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_request_data(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); -+ if (ret) -+ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!shutdown) -+ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); -+ else -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); -+ -+ if (ret) { -+ if (ret != -EAGAIN) -+ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); -+ -+ return ret; -+ } -+ -+ /* -+ * During shutdown, it is possible that the sensor has already been disabled. -+ */ -+ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) -+ return 0; -+ -+ if (rsp.status == IPTS_STATUS_TIMEOUT) -+ return -EAGAIN; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) -+{ -+ int ret = 0; -+ struct ipts_feedback cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.buffer = buffer; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * We don't know what feedback data looks like so we are sending zeros. -+ * See also ipts_control_refill_buffer. -+ */ -+ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) -+ return 0; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, -+ enum ipts_feedback_data_type type, void *data, size_t size) -+{ -+ struct ipts_feedback_header *header = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->resources.hid2me.address) -+ return -EFAULT; -+ -+ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); -+ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; -+ -+ header->cmd_type = cmd; -+ header->data_type = type; -+ header->size = size; -+ header->buffer = IPTS_HID2ME_BUFFER; -+ -+ if (size + sizeof(*header) > ipts->resources.hid2me.size) -+ return -EINVAL; -+ -+ if (data && size > 0) -+ memcpy(header->payload, data, size); -+ -+ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); -+} -+ -+int ipts_control_start(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_device_info info = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "Starting IPTS\n"); -+ -+ ret = ipts_control_get_device_info(ipts, &info); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); -+ return ret; -+ } -+ -+ ipts->info = info; -+ -+ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); -+ return ret; -+ } -+ -+ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); -+ -+ /* -+ * Handle newer devices -+ */ -+ if (info.intf_eds > 1) { -+ /* -+ * Fetching the descriptor will only work on newer devices. -+ * For older devices, a fallback descriptor will be used. -+ */ -+ ret = ipts_control_get_descriptor(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * Newer devices can be directly initialized in polling mode. -+ */ -+ ipts->mode = IPTS_MODE_POLL; -+ } -+ -+ ret = ipts_control_set_mode(ipts, ipts->mode); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_set_mem_window(ipts, &ipts->resources); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_receiver_start(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_request_data(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request data: %d\n", ret); -+ return ret; -+ } -+ -+ ipts_hid_enable(ipts); -+ -+ ret = ipts_hid_init(ipts, info); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int _ipts_control_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ipts_hid_disable(ipts); -+ dev_info(ipts->dev, "Stopping IPTS\n"); -+ -+ ret = ipts_receiver_stop(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_resources_free(&ipts->resources); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ ret = _ipts_control_stop(ipts); -+ if (ret) -+ return ret; -+ -+ ret = ipts_hid_free(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_restart(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ ret = _ipts_control_stop(ipts); -+ if (ret) -+ return ret; -+ -+ /* -+ * Wait a second to give the sensor time to fully shut down. -+ */ -+ msleep(1000); -+ -+ ret = ipts_control_start(ipts); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h -new file mode 100644 -index 000000000000..26629c5144ed ---- /dev/null -+++ b/drivers/hid/ipts/control.h -@@ -0,0 +1,126 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CONTROL_H -+#define IPTS_CONTROL_H -+ -+#include -+ -+#include "context.h" -+#include "spec-data.h" -+#include "spec-device.h" -+ -+/** -+ * ipts_control_request_flush() - Stop the data flow. -+ * @ipts: The IPTS driver context. -+ * -+ * Runs the command to stop the data flow on the device. -+ * All outstanding data needs to be acknowledged using feedback before the command will return. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_request_flush(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_flush() - Wait until data flow has been stopped. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_wait_flush(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_request_data(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_data() - Wait until new data is available. -+ * @ipts: The IPTS driver context. -+ * @block: Whether to block execution until data is available. -+ * -+ * In poll mode, this function will never return while the data flow is active. Instead, -+ * the poll will be incremented when new data is available. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. -+ */ -+int ipts_control_wait_data(struct ipts_context *ipts, bool block); -+ -+/** -+ * ipts_control_send_feedback() - Submits a feedback buffer to the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The ID of the buffer containing feedback data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); -+ -+/** -+ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. -+ * @ipts: The IPTS driver context. -+ * @cmd: The command that will be run on the device. -+ * @type: The type of the payload that is sent to the device. -+ * @data: The payload of the feedback command. -+ * @size: The size of the payload. -+ * -+ * HID2ME feedback is a special type of feedback, because it allows interfacing with -+ * the HID API of the device at any moment, without requiring a buffer that has to -+ * be acknowledged. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, -+ enum ipts_feedback_data_type type, void *data, size_t size); -+ -+/** -+ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer that has been processed and can be refilled. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) -+{ -+ /* -+ * IPTS expects structured data in the feedback buffer matching the buffer that will be -+ * refilled. We don't know what that data looks like, so we just keep the buffer empty. -+ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. -+ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling -+ * the buffers on some devices. -+ */ -+ -+ return ipts_control_send_feedback(ipts, buffer); -+} -+ -+/** -+ * ipts_control_start() - Initialized the device and starts the data flow. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_start(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_stop() - Stops the data flow and resets the device. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_stop(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_restart() - Stops the device and starts it again. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_restart(struct ipts_context *ipts); -+ -+#endif /* IPTS_CONTROL_H */ -diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h -new file mode 100644 -index 000000000000..307438c7c80c ---- /dev/null -+++ b/drivers/hid/ipts/desc.h -@@ -0,0 +1,80 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_DESC_H -+#define IPTS_DESC_H -+ -+#include -+ -+#define IPTS_HID_REPORT_SINGLETOUCH 64 -+#define IPTS_HID_REPORT_DATA 65 -+#define IPTS_HID_REPORT_SET_MODE 66 -+ -+#define IPTS_HID_REPORT_DATA_SIZE 7485 -+ -+/* -+ * HID descriptor for singletouch data. -+ * This descriptor should be present on all IPTS devices. -+ */ -+static const u8 ipts_singletouch_descriptor[] = { -+ 0x05, 0x0D, /* Usage Page (Digitizer), */ -+ 0x09, 0x04, /* Usage (Touchscreen), */ -+ 0xA1, 0x01, /* Collection (Application), */ -+ 0x85, 0x40, /* Report ID (64), */ -+ 0x09, 0x42, /* Usage (Tip Switch), */ -+ 0x15, 0x00, /* Logical Minimum (0), */ -+ 0x25, 0x01, /* Logical Maximum (1), */ -+ 0x75, 0x01, /* Report Size (1), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x95, 0x07, /* Report Count (7), */ -+ 0x81, 0x03, /* Input (Constant, Variable), */ -+ 0x05, 0x01, /* Usage Page (Desktop), */ -+ 0x09, 0x30, /* Usage (X), */ -+ 0x75, 0x10, /* Report Size (16), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0xA4, /* Push, */ -+ 0x55, 0x0E, /* Unit Exponent (14), */ -+ 0x65, 0x11, /* Unit (Centimeter), */ -+ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ -+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x09, 0x31, /* Usage (Y), */ -+ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ -+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0xB4, /* Pop, */ -+ 0xC0, /* End Collection */ -+}; -+ -+/* -+ * Fallback HID descriptor for older devices that do not have -+ * the ability to query their HID descriptor. -+ */ -+static const u8 ipts_fallback_descriptor[] = { -+ 0x05, 0x0D, /* Usage Page (Digitizer), */ -+ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ -+ 0xA1, 0x01, /* Collection (Application), */ -+ 0x85, 0x41, /* Report ID (65), */ -+ 0x09, 0x56, /* Usage (Scan Time), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0x75, 0x10, /* Report Size (16), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x09, 0x61, /* Usage (Gesture Char Quality), */ -+ 0x75, 0x08, /* Report Size (8), */ -+ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ -+ 0x81, 0x03, /* Input (Constant, Variable), */ -+ 0x85, 0x42, /* Report ID (66), */ -+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ -+ 0x09, 0xC8, /* Usage (C8h), */ -+ 0x75, 0x08, /* Report Size (8), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0xB1, 0x02, /* Feature (Variable), */ -+ 0xC0, /* End Collection, */ -+}; -+ -+#endif /* IPTS_DESC_H */ -diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c -new file mode 100644 -index 000000000000..7b9f54388a9f ---- /dev/null -+++ b/drivers/hid/ipts/eds1.c -@@ -0,0 +1,104 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "eds1.h" -+#include "spec-device.h" -+ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, -+ sizeof(ipts_fallback_descriptor)); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == mode) -+ return 0; -+ -+ ipts->mode = mode; -+ -+ ret = ipts_control_restart(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_id != IPTS_HID_REPORT_SET_MODE) -+ return -EIO; -+ -+ if (report_type != HID_FEATURE_REPORT) -+ return -EIO; -+ -+ if (size != 2) -+ return -EINVAL; -+ -+ /* -+ * Implement mode switching report for older devices without native HID support. -+ */ -+ -+ if (request_type == HID_REQ_GET_REPORT) { -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ buffer[1] = ipts->mode; -+ } else if (request_type == HID_REQ_SET_REPORT) { -+ return ipts_eds1_switch_mode(ipts, buffer[1]); -+ } else { -+ return -EIO; -+ } -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h -new file mode 100644 -index 000000000000..eeeb6575e3e8 ---- /dev/null -+++ b/drivers/hid/ipts/eds1.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "context.h" -+ -+/** -+ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds1_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type); -diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c -new file mode 100644 -index 000000000000..639940794615 ---- /dev/null -+++ b/drivers/hid/ipts/eds2.c -@@ -0,0 +1,145 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "eds2.h" -+#include "spec-data.h" -+ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, -+ ipts->descriptor.size); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ mutex_lock(&ipts->feature_lock); -+ -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ -+ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); -+ reinit_completion(&ipts->feature_event); -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ goto out; -+ } -+ -+ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); -+ if (ret == 0) { -+ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ if (!ipts->feature_report.address) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (ipts->feature_report.size > size) { -+ ret = -ETOOSMALL; -+ goto out; -+ } -+ -+ ret = ipts->feature_report.size; -+ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); -+ -+out: -+ mutex_unlock(&ipts->feature_lock); -+ return ret; -+} -+ -+static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ buffer[0] = report_id; -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; -+ else -+ return -EIO; -+ -+ if (request_type == HID_REQ_GET_REPORT) -+ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); -+ else -+ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); -+} -diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h -new file mode 100644 -index 000000000000..064e3716907a ---- /dev/null -+++ b/drivers/hid/ipts/eds2.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "context.h" -+ -+/** -+ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds2_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type); -diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c -new file mode 100644 -index 000000000000..e34a1a4f9fa7 ---- /dev/null -+++ b/drivers/hid/ipts/hid.c -@@ -0,0 +1,225 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "desc.h" -+#include "eds1.h" -+#include "eds2.h" -+#include "hid.h" -+#include "spec-data.h" -+#include "spec-hid.h" -+ -+void ipts_hid_enable(struct ipts_context *ipts) -+{ -+ WRITE_ONCE(ipts->hid_active, true); -+} -+ -+void ipts_hid_disable(struct ipts_context *ipts) -+{ -+ WRITE_ONCE(ipts->hid_active, false); -+} -+ -+static int ipts_hid_start(struct hid_device *hid) -+{ -+ return 0; -+} -+ -+static void ipts_hid_stop(struct hid_device *hid) -+{ -+} -+ -+static int ipts_hid_parse(struct hid_device *hid) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ u8 *buffer = NULL; -+ size_t size = 0; -+ -+ if (!hid) -+ return -ENODEV; -+ -+ ipts = hid->driver_data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ if (ipts->info.intf_eds == 1) -+ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); -+ else -+ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ ret = hid_parse_report(hid, buffer, size); -+ kfree(buffer); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, -+ size_t size, unsigned char report_type, int request_type) -+{ -+ struct ipts_context *ipts = NULL; -+ -+ if (!hid) -+ return -ENODEV; -+ -+ ipts = hid->driver_data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ if (ipts->info.intf_eds == 1) { -+ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } else { -+ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } -+} -+ -+static struct hid_ll_driver ipts_hid_driver = { -+ .start = ipts_hid_start, -+ .stop = ipts_hid_stop, -+ .open = ipts_hid_start, -+ .close = ipts_hid_stop, -+ .parse = ipts_hid_parse, -+ .raw_request = ipts_hid_raw_request, -+}; -+ -+int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) -+{ -+ u8 *temp = NULL; -+ struct ipts_hid_header *frame = NULL; -+ struct ipts_data_header *header = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->hid) -+ return -ENODEV; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; -+ -+ temp = ipts->resources.report.address; -+ memset(temp, 0, ipts->resources.report.size); -+ -+ if (!header) -+ return -EFAULT; -+ -+ if (header->size == 0) -+ return 0; -+ -+ if (header->type == IPTS_DATA_TYPE_HID) -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); -+ -+ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { -+ ipts->feature_report.address = header->data; -+ ipts->feature_report.size = header->size; -+ -+ complete_all(&ipts->feature_event); -+ return 0; -+ } -+ -+ if (header->type != IPTS_DATA_TYPE_FRAME) -+ return 0; -+ -+ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) -+ return -ERANGE; -+ -+ /* -+ * Synthesize a HID report matching the devices that natively send HID reports -+ */ -+ temp[0] = IPTS_HID_REPORT_DATA; -+ -+ frame = (struct ipts_hid_header *)&temp[3]; -+ frame->type = IPTS_HID_FRAME_TYPE_RAW; -+ frame->size = header->size + sizeof(*frame); -+ -+ memcpy(frame->data, header->data, header->size); -+ -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); -+} -+ -+int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->hid) -+ return 0; -+ -+ ipts->hid = hid_allocate_device(); -+ if (IS_ERR(ipts->hid)) { -+ int err = PTR_ERR(ipts->hid); -+ -+ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); -+ return err; -+ } -+ -+ ipts->hid->driver_data = ipts; -+ ipts->hid->dev.parent = ipts->dev; -+ ipts->hid->ll_driver = &ipts_hid_driver; -+ -+ ipts->hid->vendor = info.vendor; -+ ipts->hid->product = info.product; -+ ipts->hid->group = HID_GROUP_GENERIC; -+ -+ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, -+ info.product); -+ -+ ret = hid_add_device(ipts->hid); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); -+ ipts_hid_free(ipts); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_hid_free(struct ipts_context *ipts) -+{ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->hid) -+ return 0; -+ -+ hid_destroy_device(ipts->hid); -+ ipts->hid = NULL; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h -new file mode 100644 -index 000000000000..1ebe77447903 ---- /dev/null -+++ b/drivers/hid/ipts/hid.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_HID_H -+#define IPTS_HID_H -+ -+#include -+ -+#include "context.h" -+#include "spec-device.h" -+ -+void ipts_hid_enable(struct ipts_context *ipts); -+void ipts_hid_disable(struct ipts_context *ipts); -+ -+int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); -+ -+int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); -+int ipts_hid_free(struct ipts_context *ipts); -+ -+#endif /* IPTS_HID_H */ -diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c -new file mode 100644 -index 000000000000..fb5b5c13ee3e ---- /dev/null -+++ b/drivers/hid/ipts/main.c -@@ -0,0 +1,126 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "mei.h" -+#include "receiver.h" -+#include "spec-device.h" -+ -+/* -+ * The MEI client ID for IPTS functionality. -+ */ -+#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) -+ -+static int ipts_set_dma_mask(struct mei_cl_device *cldev) -+{ -+ if (!cldev) -+ return -EFAULT; -+ -+ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) -+ return 0; -+ -+ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); -+} -+ -+static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) -+ return -EFAULT; -+ -+ ret = ipts_set_dma_mask(cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mei_cldev_enable(cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); -+ return ret; -+ } -+ -+ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); -+ if (!ipts) { -+ mei_cldev_disable(cldev); -+ return -ENOMEM; -+ } -+ -+ ret = ipts_mei_init(&ipts->mei, cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); -+ return ret; -+ } -+ -+ ipts->dev = &cldev->dev; -+ ipts->mode = IPTS_MODE_EVENT; -+ -+ mutex_init(&ipts->feature_lock); -+ init_completion(&ipts->feature_event); -+ -+ mei_cldev_set_drvdata(cldev, ipts); -+ -+ ret = ipts_control_start(ipts); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void ipts_remove(struct mei_cl_device *cldev) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) { -+ pr_err("MEI device is NULL!"); -+ return; -+ } -+ -+ ipts = mei_cldev_get_drvdata(cldev); -+ -+ ret = ipts_control_stop(ipts); -+ if (ret) -+ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); -+ -+ mei_cldev_disable(cldev); -+} -+ -+static struct mei_cl_device_id ipts_device_id_table[] = { -+ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(mei, ipts_device_id_table); -+ -+static struct mei_cl_driver ipts_driver = { -+ .id_table = ipts_device_id_table, -+ .name = "ipts", -+ .probe = ipts_probe, -+ .remove = ipts_remove, -+}; -+module_mei_cl_driver(ipts_driver); -+ -+MODULE_DESCRIPTION("IPTS touchscreen driver"); -+MODULE_AUTHOR("Dorian Stoll "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c -new file mode 100644 -index 000000000000..1e0395ceae4a ---- /dev/null -+++ b/drivers/hid/ipts/mei.c -@@ -0,0 +1,188 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "mei.h" -+ -+static void locked_list_add(struct list_head *new, struct list_head *head, -+ struct rw_semaphore *lock) -+{ -+ down_write(lock); -+ list_add(new, head); -+ up_write(lock); -+} -+ -+static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) -+{ -+ down_write(lock); -+ list_del(entry); -+ up_write(lock); -+} -+ -+static void ipts_mei_incoming(struct mei_cl_device *cldev) -+{ -+ ssize_t ret = 0; -+ struct ipts_mei_message *entry = NULL; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) { -+ pr_err("MEI device is NULL!"); -+ return; -+ } -+ -+ ipts = mei_cldev_get_drvdata(cldev); -+ if (!ipts) { -+ pr_err("IPTS driver context is NULL!"); -+ return; -+ } -+ -+ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); -+ if (!entry) -+ return; -+ -+ INIT_LIST_HEAD(&entry->list); -+ -+ do { -+ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); -+ } while (ret == -EINTR); -+ -+ if (ret < 0) { -+ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); -+ return; -+ } -+ -+ if (ret == 0) { -+ dev_err(ipts->dev, "Received empty response\n"); -+ return; -+ } -+ -+ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); -+ wake_up_all(&ipts->mei.message_queue); -+} -+ -+static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, -+ struct ipts_response *rsp) -+{ -+ struct ipts_mei_message *entry = NULL; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!rsp) -+ return -EFAULT; -+ -+ down_read(&mei->message_lock); -+ -+ /* -+ * Iterate over the list of received messages, and check if there is one -+ * matching the requested command code. -+ */ -+ list_for_each_entry(entry, &mei->messages, list) { -+ if (entry->rsp.cmd == code) -+ break; -+ } -+ -+ up_read(&mei->message_lock); -+ -+ /* -+ * If entry is not the list head, this means that the loop above has been stopped early, -+ * and that we found a matching element. We drop the message from the list and return it. -+ */ -+ if (!list_entry_is_head(entry, &mei->messages, list)) { -+ locked_list_del(&entry->list, &mei->message_lock); -+ -+ *rsp = entry->rsp; -+ devm_kfree(&mei->cldev->dev, entry); -+ -+ return 0; -+ } -+ -+ return -EAGAIN; -+} -+ -+int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, -+ u64 timeout) -+{ -+ int ret = 0; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ /* -+ * A timeout of 0 means check and return immideately. -+ */ -+ if (timeout == 0) -+ return ipts_mei_search(mei, code, rsp); -+ -+ /* -+ * A timeout of less than 0 means to wait forever. -+ */ -+ if (timeout < 0) { -+ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); -+ return 0; -+ } -+ -+ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, -+ msecs_to_jiffies(timeout)); -+ -+ if (ret > 0) -+ return 0; -+ -+ return -EAGAIN; -+} -+ -+int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) -+{ -+ int ret = 0; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!mei->cldev) -+ return -EFAULT; -+ -+ if (!data) -+ return -EFAULT; -+ -+ do { -+ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); -+ } while (ret == -EINTR); -+ -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) -+{ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!cldev) -+ return -EFAULT; -+ -+ mei->cldev = cldev; -+ -+ INIT_LIST_HEAD(&mei->messages); -+ init_waitqueue_head(&mei->message_queue); -+ init_rwsem(&mei->message_lock); -+ -+ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h -new file mode 100644 -index 000000000000..973bade6b0fd ---- /dev/null -+++ b/drivers/hid/ipts/mei.h -@@ -0,0 +1,66 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_MEI_H -+#define IPTS_MEI_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "spec-device.h" -+ -+struct ipts_mei_message { -+ struct list_head list; -+ struct ipts_response rsp; -+}; -+ -+struct ipts_mei { -+ struct mei_cl_device *cldev; -+ -+ struct list_head messages; -+ -+ wait_queue_head_t message_queue; -+ struct rw_semaphore message_lock; -+}; -+ -+/** -+ * ipts_mei_recv() - Receive data from a MEI device. -+ * @mei: The IPTS MEI device context. -+ * @code: The IPTS command code to look for. -+ * @rsp: The address that the received data will be copied to. -+ * @timeout: How many milliseconds the function will wait at most. -+ * -+ * A negative timeout means to wait forever. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, -+ u64 timeout); -+ -+/** -+ * ipts_mei_send() - Send data to a MEI device. -+ * @ipts: The IPTS MEI device context. -+ * @data: The data to send. -+ * @size: The size of the data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); -+ -+/** -+ * ipts_mei_init() - Initialize the MEI device context. -+ * @mei: The MEI device context to initialize. -+ * @cldev: The MEI device the context will be bound to. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); -+ -+#endif /* IPTS_MEI_H */ -diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -new file mode 100644 -index 000000000000..977724c728c3 ---- /dev/null -+++ b/drivers/hid/ipts/receiver.c -@@ -0,0 +1,251 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "control.h" -+#include "hid.h" -+#include "receiver.h" -+#include "resources.h" -+#include "spec-device.h" -+#include "thread.h" -+ -+static void ipts_receiver_next_doorbell(struct ipts_context *ipts) -+{ -+ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; -+ *doorbell = *doorbell + 1; -+} -+ -+static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) -+{ -+ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; -+ return *doorbell; -+} -+ -+static void ipts_receiver_backoff(time64_t last, u32 n) -+{ -+ /* -+ * If the last change was less than n seconds ago, -+ * sleep for a shorter period so that new data can be -+ * processed quickly. If there was no change for more than -+ * n seconds, sleep longer to avoid wasting CPU cycles. -+ */ -+ if (last + n > ktime_get_seconds()) -+ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); -+ else -+ msleep(200); -+} -+ -+static int ipts_receiver_event_loop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ u32 buffer = 0; -+ -+ struct ipts_context *ipts = NULL; -+ time64_t last = ktime_get_seconds(); -+ -+ if (!thread) -+ return -EFAULT; -+ -+ ipts = thread->data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "IPTS running in event mode\n"); -+ -+ while (!ipts_thread_should_stop(thread)) { -+ int i = 0; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_control_wait_data(ipts, false); -+ if (ret == -EAGAIN) -+ break; -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ continue; -+ } -+ -+ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; -+ ipts_receiver_next_doorbell(ipts); -+ -+ ret = ipts_hid_input_data(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); -+ -+ ret = ipts_control_refill_buffer(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); -+ -+ ret = ipts_control_request_data(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to request data: %d\n", ret); -+ -+ last = ktime_get_seconds(); -+ } -+ -+ ipts_receiver_backoff(last, 5); -+ } -+ -+ ret = ipts_control_request_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_wait_data(ipts, true); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ ret = ipts_control_wait_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ return 0; -+} -+ -+static int ipts_receiver_poll_loop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ u32 buffer = 0; -+ -+ u32 doorbell = 0; -+ u32 lastdb = 0; -+ -+ struct ipts_context *ipts = NULL; -+ time64_t last = ktime_get_seconds(); -+ -+ if (!thread) -+ return -EFAULT; -+ -+ ipts = thread->data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "IPTS running in poll mode\n"); -+ -+ while (true) { -+ if (ipts_thread_should_stop(thread)) { -+ ret = ipts_control_request_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ doorbell = ipts_receiver_current_doorbell(ipts); -+ -+ /* -+ * After filling up one of the data buffers, IPTS will increment -+ * the doorbell. The value of the doorbell stands for the *next* -+ * buffer that IPTS is going to fill. -+ */ -+ while (lastdb != doorbell) { -+ buffer = lastdb % IPTS_BUFFERS; -+ -+ ret = ipts_hid_input_data(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); -+ -+ ret = ipts_control_refill_buffer(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); -+ -+ last = ktime_get_seconds(); -+ lastdb++; -+ } -+ -+ if (ipts_thread_should_stop(thread)) -+ break; -+ -+ ipts_receiver_backoff(last, 5); -+ } -+ -+ ret = ipts_control_wait_data(ipts, true); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ ret = ipts_control_wait_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ return 0; -+} -+ -+int ipts_receiver_start(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == IPTS_MODE_EVENT) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, -+ "ipts_event"); -+ } else if (ipts->mode == IPTS_MODE_POLL) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, -+ "ipts_poll"); -+ } else { -+ ret = -EINVAL; -+ } -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_receiver_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_thread_stop(&ipts->receiver_loop); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h -new file mode 100644 -index 000000000000..3de7da62d40c ---- /dev/null -+++ b/drivers/hid/ipts/receiver.h -@@ -0,0 +1,16 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_RECEIVER_H -+#define IPTS_RECEIVER_H -+ -+#include "context.h" -+ -+int ipts_receiver_start(struct ipts_context *ipts); -+int ipts_receiver_stop(struct ipts_context *ipts); -+ -+#endif /* IPTS_RECEIVER_H */ -diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c -new file mode 100644 -index 000000000000..cc14653b2a9f ---- /dev/null -+++ b/drivers/hid/ipts/resources.c -@@ -0,0 +1,131 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+ -+#include "desc.h" -+#include "resources.h" -+#include "spec-device.h" -+ -+static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) -+{ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (buffer->address) -+ return 0; -+ -+ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); -+ -+ if (!buffer->address) -+ return -ENOMEM; -+ -+ buffer->size = size; -+ buffer->device = dev; -+ -+ return 0; -+} -+ -+static void ipts_resources_free_buffer(struct ipts_buffer *buffer) -+{ -+ if (!buffer->address) -+ return; -+ -+ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); -+ -+ buffer->address = NULL; -+ buffer->size = 0; -+ -+ buffer->dma_address = 0; -+ buffer->device = NULL; -+} -+ -+int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) -+{ -+ int ret = 0; -+ -+ /* -+ * Some compilers (AOSP clang) complain about a redefined -+ * variable when this is declared inside of the for loop. -+ */ -+ int i = 0; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); -+ if (ret) -+ goto err; -+ } -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); -+ if (ret) -+ goto err; -+ } -+ -+ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); -+ if (ret) -+ goto err; -+ -+ if (!res->report.address) { -+ res->report.size = IPTS_HID_REPORT_DATA_SIZE; -+ res->report.address = kzalloc(res->report.size, GFP_KERNEL); -+ -+ if (!res->report.address) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } -+ -+ return 0; -+ -+err: -+ -+ ipts_resources_free(res); -+ return ret; -+} -+ -+int ipts_resources_free(struct ipts_resources *res) -+{ -+ int i = 0; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) -+ ipts_resources_free_buffer(&res->data[i]); -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) -+ ipts_resources_free_buffer(&res->feedback[i]); -+ -+ ipts_resources_free_buffer(&res->doorbell); -+ ipts_resources_free_buffer(&res->workqueue); -+ ipts_resources_free_buffer(&res->hid2me); -+ ipts_resources_free_buffer(&res->descriptor); -+ -+ kfree(res->report.address); -+ res->report.address = NULL; -+ res->report.size = 0; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h -new file mode 100644 -index 000000000000..2068e13285f0 ---- /dev/null -+++ b/drivers/hid/ipts/resources.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_RESOURCES_H -+#define IPTS_RESOURCES_H -+ -+#include -+#include -+ -+#include "spec-device.h" -+ -+struct ipts_buffer { -+ u8 *address; -+ size_t size; -+ -+ dma_addr_t dma_address; -+ struct device *device; -+}; -+ -+struct ipts_resources { -+ struct ipts_buffer data[IPTS_BUFFERS]; -+ struct ipts_buffer feedback[IPTS_BUFFERS]; -+ -+ struct ipts_buffer doorbell; -+ struct ipts_buffer workqueue; -+ struct ipts_buffer hid2me; -+ -+ struct ipts_buffer descriptor; -+ -+ // Buffer for synthesizing HID reports -+ struct ipts_buffer report; -+}; -+ -+int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); -+int ipts_resources_free(struct ipts_resources *res); -+ -+#endif /* IPTS_RESOURCES_H */ -diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h -new file mode 100644 -index 000000000000..e8dd98895a7e ---- /dev/null -+++ b/drivers/hid/ipts/spec-data.h -@@ -0,0 +1,100 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_DATA_H -+#define IPTS_SPEC_DATA_H -+ -+#include -+#include -+ -+/** -+ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. -+ */ -+enum ipts_feedback_cmd_type { -+ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, -+ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, -+ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, -+}; -+ -+/** -+ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. -+ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. -+ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. -+ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. -+ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. -+ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. -+ */ -+enum ipts_feedback_data_type { -+ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, -+ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, -+ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, -+ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, -+ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, -+}; -+ -+/** -+ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. -+ * @cmd_type: A command that should be executed on the sensor. -+ * @size: The size of the payload to be written. -+ * @buffer: The ID of the buffer that contains this feedback data. -+ * @protocol: The protocol version of the EDS. -+ * @data_type: The type of data that the buffer contains. -+ * @spi_offset: The offset at which to write the payload data to the sensor. -+ * @payload: Payload for the feedback command, or 0 if no payload is sent. -+ */ -+struct ipts_feedback_header { -+ enum ipts_feedback_cmd_type cmd_type; -+ u32 size; -+ u32 buffer; -+ u32 protocol; -+ enum ipts_feedback_data_type data_type; -+ u32 spi_offset; -+ u8 reserved[40]; -+ u8 payload[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_feedback_header) == 64); -+ -+/** -+ * enum ipts_data_type - Defines what type of data a buffer contains. -+ * @IPTS_DATA_TYPE_FRAME: Raw data frame. -+ * @IPTS_DATA_TYPE_ERROR: Error data. -+ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. -+ * @IPTS_DATA_TYPE_HID: A HID report. -+ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. -+ */ -+enum ipts_data_type { -+ IPTS_DATA_TYPE_FRAME = 0x00, -+ IPTS_DATA_TYPE_ERROR = 0x01, -+ IPTS_DATA_TYPE_VENDOR = 0x02, -+ IPTS_DATA_TYPE_HID = 0x03, -+ IPTS_DATA_TYPE_GET_FEATURES = 0x04, -+ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, -+}; -+ -+/** -+ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. -+ * @type: What data the buffer contains. -+ * @size: How much data the buffer contains. -+ * @buffer: Which buffer the data is in. -+ */ -+struct ipts_data_header { -+ enum ipts_data_type type; -+ u32 size; -+ u32 buffer; -+ u8 reserved[52]; -+ u8 data[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_data_header) == 64); -+ -+#endif /* IPTS_SPEC_DATA_H */ -diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h -new file mode 100644 -index 000000000000..41845f9d9025 ---- /dev/null -+++ b/drivers/hid/ipts/spec-device.h -@@ -0,0 +1,290 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_DEVICE_H -+#define IPTS_SPEC_DEVICE_H -+ -+#include -+#include -+ -+/* -+ * The amount of buffers that IPTS can use for data transfer. -+ */ -+#define IPTS_BUFFERS 16 -+ -+/* -+ * The buffer ID that is used for HID2ME feedback -+ */ -+#define IPTS_HID2ME_BUFFER IPTS_BUFFERS -+ -+/** -+ * enum ipts_command - Commands that can be sent to the IPTS hardware. -+ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. -+ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. -+ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. -+ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. -+ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. -+ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. -+ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. -+ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. -+ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. -+ */ -+enum ipts_command_code { -+ IPTS_CMD_GET_DEVICE_INFO = 0x01, -+ IPTS_CMD_SET_MODE = 0x02, -+ IPTS_CMD_SET_MEM_WINDOW = 0x03, -+ IPTS_CMD_QUIESCE_IO = 0x04, -+ IPTS_CMD_READY_FOR_DATA = 0x05, -+ IPTS_CMD_FEEDBACK = 0x06, -+ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, -+ IPTS_CMD_RESET_SENSOR = 0x0B, -+ IPTS_CMD_GET_DESCRIPTOR = 0x0F, -+}; -+ -+/** -+ * enum ipts_status - Possible status codes returned by the IPTS device. -+ * @IPTS_STATUS_SUCCESS: Operation completed successfully. -+ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. -+ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. -+ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. -+ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. -+ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. -+ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. -+ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. -+ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. -+ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. -+ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. -+ * The host can ignore this error and attempt to continue. -+ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. -+ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. -+ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. -+ * @IPTS_STATUS_TIMEOUT: The operation timed out. -+ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. -+ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. -+ * Further progress is not possible. -+ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. -+ * The driver can attempt to continue. -+ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. -+ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. -+ */ -+enum ipts_status { -+ IPTS_STATUS_SUCCESS = 0x00, -+ IPTS_STATUS_INVALID_PARAMS = 0x01, -+ IPTS_STATUS_ACCESS_DENIED = 0x02, -+ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, -+ IPTS_STATUS_NOT_READY = 0x04, -+ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, -+ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, -+ IPTS_STATUS_OUT_OF_MEMORY = 0x07, -+ IPTS_STATUS_INTERNAL_ERROR = 0x08, -+ IPTS_STATUS_SENSOR_DISABLED = 0x09, -+ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, -+ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, -+ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, -+ IPTS_STATUS_RESET_FAILED = 0x0D, -+ IPTS_STATUS_TIMEOUT = 0x0E, -+ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, -+ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, -+ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, -+ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, -+ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, -+}; -+ -+/** -+ * struct ipts_command - Message that is sent to the device for calling a command. -+ * @cmd: The command that will be called. -+ * @payload: Payload containing parameters for the called command. -+ */ -+struct ipts_command { -+ enum ipts_command_code cmd; -+ u8 payload[320]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_command) == 324); -+ -+/** -+ * enum ipts_mode - Configures what data the device produces and how its sent. -+ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. -+ * Older devices will return singletouch data in this mode. -+ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. -+ * Older devices will return multitouch data in this mode. -+ */ -+enum ipts_mode { -+ IPTS_MODE_EVENT = 0x00, -+ IPTS_MODE_POLL = 0x01, -+}; -+ -+/** -+ * struct ipts_set_mode - Payload for the SET_MODE command. -+ * @mode: Changes the mode that IPTS will operate in. -+ */ -+struct ipts_set_mode { -+ enum ipts_mode mode; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_set_mode) == 16); -+ -+#define IPTS_WORKQUEUE_SIZE 8192 -+#define IPTS_WORKQUEUE_ITEM_SIZE 16 -+ -+/** -+ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. -+ * @data_addr_lower: Lower 32 bits of the data buffer addresses. -+ * @data_addr_upper: Upper 32 bits of the data buffer addresses. -+ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. -+ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. -+ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. -+ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. -+ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. -+ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. -+ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. -+ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. -+ * @hid2me_size: Size of the hid2me feedback buffer. -+ * @workqueue_item_size: Magic value. Must be 16. -+ * @workqueue_size: Magic value. Must be 8192. -+ * -+ * The workqueue related items in this struct are required for using -+ * GuC submission with binary processing firmware. Since this driver does -+ * not use GuC submission and instead exports raw data to userspace, these -+ * items are not actually used, but they need to be allocated and passed -+ * to the device, otherwise initialization will fail. -+ */ -+struct ipts_mem_window { -+ u32 data_addr_lower[IPTS_BUFFERS]; -+ u32 data_addr_upper[IPTS_BUFFERS]; -+ u32 workqueue_addr_lower; -+ u32 workqueue_addr_upper; -+ u32 doorbell_addr_lower; -+ u32 doorbell_addr_upper; -+ u32 feedback_addr_lower[IPTS_BUFFERS]; -+ u32 feedback_addr_upper[IPTS_BUFFERS]; -+ u32 hid2me_addr_lower; -+ u32 hid2me_addr_upper; -+ u32 hid2me_size; -+ u8 reserved1; -+ u8 workqueue_item_size; -+ u16 workqueue_size; -+ u8 reserved[32]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_mem_window) == 320); -+ -+/** -+ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. -+ */ -+struct ipts_quiesce_io { -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_quiesce_io) == 12); -+ -+/** -+ * struct ipts_feedback - Payload for the FEEDBACK command. -+ * @buffer: The buffer that the device should refill. -+ */ -+struct ipts_feedback { -+ u32 buffer; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_feedback) == 16); -+ -+/** -+ * enum ipts_reset_type - Possible ways of resetting the device. -+ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. -+ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. -+ */ -+enum ipts_reset_type { -+ IPTS_RESET_TYPE_HARD = 0x00, -+ IPTS_RESET_TYPE_SOFT = 0x01, -+}; -+ -+/** -+ * struct ipts_reset - Payload for the RESET_SENSOR command. -+ * @type: How the device should get reset. -+ */ -+struct ipts_reset_sensor { -+ enum ipts_reset_type type; -+ u8 reserved[4]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_reset_sensor) == 8); -+ -+/** -+ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. -+ * @addr_lower: The lower 32 bits of the descriptor buffer address. -+ * @addr_upper: The upper 32 bits of the descriptor buffer address. -+ * @magic: A magic value. Must be 8. -+ */ -+struct ipts_get_descriptor { -+ u32 addr_lower; -+ u32 addr_upper; -+ u32 magic; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_get_descriptor) == 24); -+ -+/* -+ * The type of a response is indicated by a -+ * command code, with the most significant bit flipped to 1. -+ */ -+#define IPTS_RSP_BIT BIT(31) -+ -+/** -+ * struct ipts_response - Data returned from the device in response to a command. -+ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). -+ * @status: The return code of the command. -+ * @payload: The data that was produced by the command. -+ */ -+struct ipts_response { -+ enum ipts_command_code cmd; -+ enum ipts_status status; -+ u8 payload[80]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_response) == 88); -+ -+/** -+ * struct ipts_device_info - Vendor information of the IPTS device. -+ * @vendor: Vendor ID of this device. -+ * @product: Product ID of this device. -+ * @hw_version: Hardware revision of this device. -+ * @fw_version: Firmware revision of this device. -+ * @data_size: Requested size for a data buffer. -+ * @feedback_size: Requested size for a feedback buffer. -+ * @mode: Mode that the device currently operates in. -+ * @max_contacts: Maximum amount of concurrent touches the sensor can process. -+ * @sensor_min_eds: The minimum EDS version supported by the sensor. -+ * @sensor_max_eds: The maximum EDS version supported by the sensor. -+ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. -+ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. -+ * @intf_eds: The EDS version implemented by the interface between ME and host. -+ */ -+struct ipts_device_info { -+ u16 vendor; -+ u16 product; -+ u32 hw_version; -+ u32 fw_version; -+ u32 data_size; -+ u32 feedback_size; -+ enum ipts_mode mode; -+ u8 max_contacts; -+ u8 reserved1[3]; -+ u8 sensor_min_eds; -+ u8 sensor_maj_eds; -+ u8 me_min_eds; -+ u8 me_maj_eds; -+ u8 intf_eds; -+ u8 reserved2[11]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_device_info) == 44); -+ -+#endif /* IPTS_SPEC_DEVICE_H */ -diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h -new file mode 100644 -index 000000000000..5a58d4a0a610 ---- /dev/null -+++ b/drivers/hid/ipts/spec-hid.h -@@ -0,0 +1,34 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_HID_H -+#define IPTS_SPEC_HID_H -+ -+#include -+#include -+ -+/* -+ * Made-up type for passing raw IPTS data in a HID report. -+ */ -+#define IPTS_HID_FRAME_TYPE_RAW 0xEE -+ -+/** -+ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. -+ * @size: Size of the data inside the report, including this header. -+ * @type: What type of data does this report contain. -+ */ -+struct ipts_hid_header { -+ u32 size; -+ u8 reserved1; -+ u8 type; -+ u8 reserved2; -+ u8 data[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_hid_header) == 7); -+ -+#endif /* IPTS_SPEC_HID_H */ -diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c -new file mode 100644 -index 000000000000..355e92bea26f ---- /dev/null -+++ b/drivers/hid/ipts/thread.c -@@ -0,0 +1,84 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "thread.h" -+ -+bool ipts_thread_should_stop(struct ipts_thread *thread) -+{ -+ if (!thread) -+ return false; -+ -+ return READ_ONCE(thread->should_stop); -+} -+ -+static int ipts_thread_runner(void *data) -+{ -+ int ret = 0; -+ struct ipts_thread *thread = data; -+ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!thread->threadfn) -+ return -EFAULT; -+ -+ ret = thread->threadfn(thread); -+ complete_all(&thread->done); -+ -+ return ret; -+} -+ -+int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), -+ void *data, const char *name) -+{ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!threadfn) -+ return -EFAULT; -+ -+ init_completion(&thread->done); -+ -+ thread->data = data; -+ thread->should_stop = false; -+ thread->threadfn = threadfn; -+ -+ thread->thread = kthread_run(ipts_thread_runner, thread, name); -+ return PTR_ERR_OR_ZERO(thread->thread); -+} -+ -+int ipts_thread_stop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!thread->thread) -+ return 0; -+ -+ WRITE_ONCE(thread->should_stop, true); -+ -+ /* -+ * Make sure that the write has gone through before waiting. -+ */ -+ wmb(); -+ -+ wait_for_completion(&thread->done); -+ ret = kthread_stop(thread->thread); -+ -+ thread->thread = NULL; -+ thread->data = NULL; -+ thread->threadfn = NULL; -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h -new file mode 100644 -index 000000000000..1f966b8b32c4 ---- /dev/null -+++ b/drivers/hid/ipts/thread.h -@@ -0,0 +1,59 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_THREAD_H -+#define IPTS_THREAD_H -+ -+#include -+#include -+#include -+ -+/* -+ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible -+ * to issue MEI commands from that thread while it shuts itself down. By using a custom -+ * boolean variable and a completion object, we can call kthread_stop only when the thread -+ * already finished all of its work and has returned. -+ */ -+struct ipts_thread { -+ struct task_struct *thread; -+ -+ bool should_stop; -+ struct completion done; -+ -+ void *data; -+ int (*threadfn)(struct ipts_thread *thread); -+}; -+ -+/** -+ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. -+ * @thread: The current thread. -+ * -+ * Returns: true if the thread should stop, false if not. -+ */ -+bool ipts_thread_should_stop(struct ipts_thread *thread); -+ -+/** -+ * ipts_thread_start() - Starts an IPTS thread. -+ * @thread: The thread to initialize and start. -+ * @threadfn: The function to execute. -+ * @data: An argument that will be passed to threadfn. -+ * @name: The name of the new thread. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), -+ void *data, const char name[]); -+ -+/** -+ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. -+ * @thread: The thread that should stop. -+ * -+ * Returns: The return value of the thread function. -+ */ -+int ipts_thread_stop(struct ipts_thread *thread); -+ -+#endif /* IPTS_THREAD_H */ --- -2.47.1 - diff --git a/patches/6.14-rc2/0006-ithc.patch b/patches/6.14-rc2/0006-ithc.patch deleted file mode 100644 index 37c29e7924..0000000000 --- a/patches/6.14-rc2/0006-ithc.patch +++ /dev/null @@ -1,2773 +0,0 @@ -From d07e07e448b9b1ac7102911263626b623f138a28 Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Sun, 11 Dec 2022 12:03:38 +0100 -Subject: [PATCH] iommu: intel: Disable source id verification for ITHC - -Signed-off-by: Dorian Stoll -Patchset: ithc ---- - drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 7a6d188e3bea..0179baee4596 100644 ---- a/drivers/iommu/intel/irq_remapping.c -+++ b/drivers/iommu/intel/irq_remapping.c -@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) - data.busmatch_count = 0; - pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); - -+ /* -+ * The Intel Touch Host Controller is at 00:10.6, but for some reason -+ * the MSI interrupts have request id 01:05.0. -+ * Disable id verification to work around this. -+ * FIXME Find proper fix or turn this into a quirk. -+ */ -+ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { -+ switch(dev->device) { -+ case 0x98d0: case 0x98d1: // LKF -+ case 0xa0d0: case 0xa0d1: // TGL LP -+ case 0x43d0: case 0x43d1: // TGL H -+ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); -+ return 0; -+ } -+ } -+ - /* - * DMA alias provides us with a PCI device and alias. The only case - * where the it will return an alias on a different bus than the --- -2.47.1 - -From 280c63dff160b59d1cbac71a63dc7f16d335fec9 Mon Sep 17 00:00:00 2001 -From: quo -Date: Sun, 11 Dec 2022 12:10:54 +0100 -Subject: [PATCH] hid: Add support for Intel Touch Host Controller - -Based on quo/ithc-linux@34539af4726d. - -Signed-off-by: Maximilian Stoll -Patchset: ithc ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 1 + - drivers/hid/ithc/Kbuild | 6 + - drivers/hid/ithc/Kconfig | 12 + - drivers/hid/ithc/ithc-debug.c | 149 ++++++++ - drivers/hid/ithc/ithc-debug.h | 7 + - drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ - drivers/hid/ithc/ithc-dma.h | 47 +++ - drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ - drivers/hid/ithc/ithc-hid.h | 32 ++ - drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ - drivers/hid/ithc/ithc-legacy.h | 8 + - drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.h | 39 ++ - drivers/hid/ithc/ithc-regs.c | 154 ++++++++ - drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ - drivers/hid/ithc/ithc.h | 89 +++++ - 18 files changed, 2568 insertions(+) - create mode 100644 drivers/hid/ithc/Kbuild - create mode 100644 drivers/hid/ithc/Kconfig - create mode 100644 drivers/hid/ithc/ithc-debug.c - create mode 100644 drivers/hid/ithc/ithc-debug.h - create mode 100644 drivers/hid/ithc/ithc-dma.c - create mode 100644 drivers/hid/ithc/ithc-dma.h - create mode 100644 drivers/hid/ithc/ithc-hid.c - create mode 100644 drivers/hid/ithc/ithc-hid.h - create mode 100644 drivers/hid/ithc/ithc-legacy.c - create mode 100644 drivers/hid/ithc/ithc-legacy.h - create mode 100644 drivers/hid/ithc/ithc-main.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.h - create mode 100644 drivers/hid/ithc/ithc-regs.c - create mode 100644 drivers/hid/ithc/ithc-regs.h - create mode 100644 drivers/hid/ithc/ithc.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 38eb29e4cc31..76ad7d9143c7 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1375,4 +1375,6 @@ source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/ipts/Kconfig" - -+source "drivers/hid/ithc/Kconfig" -+ - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 02588e5d01eb..1ea3d2e0d4e9 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -173,5 +173,6 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - - obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ - - obj-$(CONFIG_HID_IPTS) += ipts/ -+obj-$(CONFIG_HID_ITHC) += ithc/ -diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild -new file mode 100644 -index 000000000000..4937ba131297 ---- /dev/null -+++ b/drivers/hid/ithc/Kbuild -@@ -0,0 +1,6 @@ -+obj-$(CONFIG_HID_ITHC) := ithc.o -+ -+ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o -+ -+ccflags-y := -std=gnu11 -Wno-declaration-after-statement -+ -diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig -new file mode 100644 -index 000000000000..ede713023609 ---- /dev/null -+++ b/drivers/hid/ithc/Kconfig -@@ -0,0 +1,12 @@ -+config HID_ITHC -+ tristate "Intel Touch Host Controller" -+ depends on PCI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Touch Host Controller (ITHC / IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ithc. -diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c -new file mode 100644 -index 000000000000..2d8c6afe9966 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.c -@@ -0,0 +1,149 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+void ithc_log_regs(struct ithc *ithc) -+{ -+ if (!ithc->prev_regs) -+ return; -+ u32 __iomem *cur = (__iomem void *)ithc->regs; -+ u32 *prev = (void *)ithc->prev_regs; -+ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { -+ u32 x = readl(cur + i); -+ if (x != prev[i]) { -+ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); -+ prev[i] = x; -+ } -+ } -+} -+ -+static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, -+ loff_t *offset) -+{ -+ // Debug commands consist of a single letter followed by a list of numbers (decimal or -+ // hexadecimal, space-separated). -+ struct ithc *ithc = file_inode(f)->i_private; -+ char cmd[256]; -+ if (!ithc || !ithc->pci) -+ return -ENODEV; -+ if (!len) -+ return -EINVAL; -+ if (len >= sizeof(cmd)) -+ return -EINVAL; -+ if (copy_from_user(cmd, buf, len)) -+ return -EFAULT; -+ cmd[len] = 0; -+ if (cmd[len-1] == '\n') -+ cmd[len-1] = 0; -+ pci_info(ithc->pci, "debug command: %s\n", cmd); -+ -+ // Parse the list of arguments into a u32 array. -+ u32 n = 0; -+ const char *s = cmd + 1; -+ u32 a[32]; -+ while (*s && *s != '\n') { -+ if (n >= ARRAY_SIZE(a)) -+ return -EINVAL; -+ if (*s++ != ' ') -+ return -EINVAL; -+ char *e; -+ a[n++] = simple_strtoul(s, &e, 0); -+ if (e == s) -+ return -EINVAL; -+ s = e; -+ } -+ ithc_log_regs(ithc); -+ -+ // Execute the command. -+ switch (cmd[0]) { -+ case 'x': // reset -+ ithc_reset(ithc); -+ break; -+ case 'w': // write register: offset mask value -+ if (n != 3 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", -+ a[0], a[2], a[1]); -+ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); -+ break; -+ case 'r': // read register: offset -+ if (n != 1 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], -+ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); -+ break; -+ case 's': // spi command: cmd offset len data... -+ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ // set touch cfg: s 6 12 4 XX -+ if (n < 3 || a[2] > (n - 3) * 4) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); -+ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) -+ for (u32 i = 0; i < (a[2] + 3) / 4; i++) -+ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); -+ break; -+ case 'd': // dma command: cmd len data... -+ // get report descriptor: d 7 8 0 0 -+ // enable multitouch: d 3 2 0x0105 -+ if (n < 1) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); -+ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; -+ if (ithc_dma_tx(ithc, &data)) -+ pci_err(ithc->pci, "dma tx failed\n"); -+ break; -+ default: -+ return -EINVAL; -+ } -+ ithc_log_regs(ithc); -+ return len; -+} -+ -+static struct dentry *dbg_dir; -+ -+void __init ithc_debug_init_module(void) -+{ -+ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); -+ if (IS_ERR(d)) -+ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); -+ else -+ dbg_dir = d; -+} -+ -+void __exit ithc_debug_exit_module(void) -+{ -+ debugfs_remove_recursive(dbg_dir); -+ dbg_dir = NULL; -+} -+ -+static const struct file_operations ithc_debugfops_cmd = { -+ .owner = THIS_MODULE, -+ .write = ithc_debugfs_cmd_write, -+}; -+ -+static void ithc_debugfs_devres_release(struct device *dev, void *res) -+{ -+ struct dentry **dbgm = res; -+ debugfs_remove_recursive(*dbgm); -+} -+ -+int ithc_debug_init_device(struct ithc *ithc) -+{ -+ if (!dbg_dir) -+ return -ENOENT; -+ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); -+ if (!dbgm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, dbgm); -+ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); -+ if (IS_ERR(dbg)) -+ return PTR_ERR(dbg); -+ *dbgm = dbg; -+ -+ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); -+ if (IS_ERR(cmd)) -+ return PTR_ERR(cmd); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h -new file mode 100644 -index 000000000000..38c53d916bdb ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.h -@@ -0,0 +1,7 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+void ithc_debug_init_module(void); -+void ithc_debug_exit_module(void); -+int ithc_debug_init_device(struct ithc *ithc); -+void ithc_log_regs(struct ithc *ithc); -+ -diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c -new file mode 100644 -index 000000000000..bf4eab33062b ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.c -@@ -0,0 +1,312 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. -+// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. -+// This allows each data buffer to consist of multiple non-contiguous blocks of memory. -+ -+static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, -+ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) -+{ -+ p->num_pages = num_pages; -+ p->dir = dir; -+ // We allocate enough space to have one PRD per data buffer page, however if the data -+ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so -+ // some will remain unused (which is fine). -+ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); -+ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); -+ if (!p->addr) -+ return -ENOMEM; -+ if (p->dma_addr & (PAGE_SIZE - 1)) -+ return -EFAULT; -+ return 0; -+} -+ -+// Devres managed sg_table wrapper. -+struct ithc_sg_table { -+ void *addr; -+ struct sg_table sgt; -+ enum dma_data_direction dir; -+}; -+static void ithc_dma_sgtable_free(struct sg_table *sgt) -+{ -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_sg(sgt, sg, i) { -+ struct page *p = sg_page(sg); -+ if (p) -+ __free_page(p); -+ } -+ sg_free_table(sgt); -+} -+static void ithc_dma_data_devres_release(struct device *dev, void *res) -+{ -+ struct ithc_sg_table *sgt = res; -+ if (sgt->addr) -+ vunmap(sgt->addr); -+ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); -+ ithc_dma_sgtable_free(&sgt->sgt); -+} -+ -+static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b) -+{ -+ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be -+ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). -+ // We could use dma_alloc_noncontiguous(), however this still always allocates a single -+ // DMA mapped segment, which is more restrictive than what we need. -+ // Instead we use an sg_table of individually allocated pages. -+ struct page *pages[16]; -+ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) -+ return -EINVAL; -+ b->active_idx = -1; -+ struct ithc_sg_table *sgt = devres_alloc( -+ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); -+ if (!sgt) -+ return -ENOMEM; -+ sgt->dir = prds->dir; -+ -+ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { -+ struct scatterlist *sg; -+ int i; -+ bool ok = true; -+ for_each_sgtable_sg(&sgt->sgt, sg, i) { -+ // NOTE: don't need __GFP_DMA for PCI DMA -+ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); -+ if (!p) { -+ ok = false; -+ break; -+ } -+ sg_set_page(sg, p, PAGE_SIZE, 0); -+ } -+ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { -+ devres_add(&ithc->pci->dev, sgt); -+ b->sgt = &sgt->sgt; -+ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); -+ if (!b->addr) -+ return -ENOMEM; -+ return 0; -+ } -+ ithc_dma_sgtable_free(&sgt->sgt); -+ } -+ devres_free(sgt); -+ return -ENOMEM; -+} -+ -+static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Give a buffer to the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ if (b->active_idx >= 0) { -+ pci_err(ithc->pci, "buffer already active\n"); -+ return -EINVAL; -+ } -+ b->active_idx = idx; -+ if (prds->dir == DMA_TO_DEVICE) { -+ // TX buffer: Caller should have already filled the data buffer, so just fill -+ // the PRD and flush. -+ // (TODO: Support multi-page TX buffers. So far no device seems to use or need -+ // these though.) -+ if (b->data_size > PAGE_SIZE) -+ return -EINVAL; -+ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; -+ prd->size = b->data_size | PRD_FLAG_END; -+ flush_kernel_vmap_range(b->addr, b->data_size); -+ } else if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Reset PRDs. -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ prd->addr = sg_dma_address(sg) >> 10; -+ prd->size = sg_dma_len(sg); -+ prd++; -+ } -+ prd[-1].size |= PRD_FLAG_END; -+ } -+ dma_wmb(); // for the prds -+ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Take a buffer from the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ // This is purely a sanity check. We don't strictly need the idx parameter for this -+ // function, because it should always be the same as active_idx, unless we have a bug. -+ if (b->active_idx != idx) { -+ pci_err(ithc->pci, "wrong buffer index\n"); -+ return -EINVAL; -+ } -+ b->active_idx = -1; -+ if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Calculate actual received data size from PRDs. -+ dma_rmb(); // for the prds -+ b->data_size = 0; -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ unsigned int size = prd->size; -+ b->data_size += size & PRD_SIZE_MASK; -+ if (size & PRD_FLAG_END) -+ break; -+ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { -+ pci_err(ithc->pci, "truncated prd\n"); -+ break; -+ } -+ prd++; -+ } -+ invalidate_kernel_vmap_range(b->addr, b->data_size); -+ } -+ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_init(&rx->mutex); -+ -+ // Allocate buffers. -+ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", -+ NUM_RX_BUF, ithc->max_rx_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); -+ -+ // Init registers. -+ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); -+ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); -+ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); -+ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); -+ u8 head = readb(&ithc->regs->dma_rx[channel].head); -+ if (head) { -+ pci_err(ithc->pci, "head is nonzero (%u)\n", head); -+ return -EIO; -+ } -+ -+ // Init buffers. -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); -+ -+ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); -+ return 0; -+} -+ -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) -+{ -+ bitsb_set(&ithc->regs->dma_rx[channel].control, -+ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, -+ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); -+} -+ -+int ithc_dma_tx_init(struct ithc *ithc) -+{ -+ struct ithc_dma_tx *tx = &ithc->dma_tx; -+ mutex_init(&tx->mutex); -+ -+ // Allocate buffers. -+ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", -+ ithc->max_tx_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); -+ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); -+ -+ // Init registers. -+ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); -+ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); -+ -+ // Init buffers. -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ return 0; -+} -+ -+static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) -+{ -+ // Process all filled RX buffers from the ringbuffer. -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ unsigned int n = rx->num_received; -+ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); -+ while (1) { -+ u8 tail = n % NUM_RX_BUF; -+ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); -+ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); -+ // ringbuffer is full if tail_wrap == head_wrap -+ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG -+ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) -+ return 0; -+ -+ // take the buffer that the device just filled -+ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); -+ rx->num_received = ++n; -+ -+ // process data -+ struct ithc_data d; -+ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) -+ (ithc, b->addr, b->data_size, &d) < 0) { -+ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", -+ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); -+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -+ b->addr, min(b->data_size, 0x400u), 0); -+ } else { -+ ithc_hid_process_data(ithc, &d); -+ } -+ -+ // give the buffer back to the device -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); -+ } -+} -+int ithc_dma_rx(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_lock(&rx->mutex); -+ int ret = ithc_dma_rx_unlocked(ithc, channel); -+ mutex_unlock(&rx->mutex); -+ return ret; -+} -+ -+static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) -+{ -+ // Send a single TX buffer to the THC. -+ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ -+ // Fill the TX buffer with header and data. -+ ssize_t sz; -+ if (data->type == ITHC_DATA_RAW) { -+ sz = min(data->size, ithc->max_tx_size); -+ memcpy(ithc->dma_tx.buf.addr, data->data, sz); -+ } else { -+ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) -+ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); -+ } -+ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ if (sz < 0) { -+ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", -+ data->type, data->size, (int)sz); -+ return -EINVAL; -+ } -+ -+ // Let the THC process the buffer. -+ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); -+ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); -+ return 0; -+} -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) -+{ -+ mutex_lock(&ithc->dma_tx.mutex); -+ int ret = ithc_dma_tx_unlocked(ithc, data); -+ mutex_unlock(&ithc->dma_tx.mutex); -+ return ret; -+} -+ -diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h -new file mode 100644 -index 000000000000..1749a5819b3e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define PRD_SIZE_MASK 0xffffff -+#define PRD_FLAG_END 0x1000000 -+#define PRD_FLAG_SUCCESS 0x2000000 -+#define PRD_FLAG_ERROR 0x4000000 -+ -+struct ithc_phys_region_desc { -+ u64 addr; // physical addr/1024 -+ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds -+ u32 unused; -+}; -+ -+struct ithc_dma_prd_buffer { -+ void *addr; -+ dma_addr_t dma_addr; -+ u32 size; -+ u32 num_pages; // per data buffer -+ enum dma_data_direction dir; -+}; -+ -+struct ithc_dma_data_buffer { -+ void *addr; -+ struct sg_table *sgt; -+ int active_idx; -+ u32 data_size; -+}; -+ -+struct ithc_dma_tx { -+ struct mutex mutex; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer buf; -+}; -+ -+struct ithc_dma_rx { -+ struct mutex mutex; -+ u32 num_received; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; -+}; -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel); -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); -+int ithc_dma_tx_init(struct ithc *ithc); -+int ithc_dma_rx(struct ithc *ithc, u8 channel); -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); -+ -diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c -new file mode 100644 -index 000000000000..065646ab499e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.c -@@ -0,0 +1,207 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+static int ithc_hid_start(struct hid_device *hdev) { return 0; } -+static void ithc_hid_stop(struct hid_device *hdev) { } -+static int ithc_hid_open(struct hid_device *hdev) { return 0; } -+static void ithc_hid_close(struct hid_device *hdev) { } -+ -+static int ithc_hid_parse(struct hid_device *hdev) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; -+ WRITE_ONCE(ithc->hid.parse_done, false); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); -+ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), -+ msecs_to_jiffies(200))) { -+ ithc_log_regs(ithc); -+ return 0; -+ } -+ if (retries > 5) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "failed to read report descriptor\n"); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -+ } -+} -+ -+static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -+ size_t len, unsigned char rtype, int reqtype) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ if (!buf || !len) -+ return -EINVAL; -+ -+ struct ithc_data d = { .size = len, .data = buf }; -+ buf[0] = reportnum; -+ -+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_OUTPUT_REPORT; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_SET_FEATURE; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -+ d.type = ITHC_DATA_GET_FEATURE; -+ d.data = &reportnum; -+ d.size = 1; -+ -+ // Prepare for response. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = buf; -+ ithc->hid.get_feature_size = len; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ -+ // Transmit 'get feature' request. -+ int r = CHECK(ithc_dma_tx, ithc, &d); -+ if (!r) { -+ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, -+ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); -+ if (!r) -+ r = -ETIMEDOUT; -+ else if (r < 0) -+ r = -EINTR; -+ else -+ r = 0; -+ } -+ -+ // If everything went ok, the buffer has been filled with the response data. -+ // Return the response size. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = NULL; -+ if (!r) -+ r = ithc->hid.get_feature_size; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ return r; -+ } -+ -+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -+ rtype, reqtype, reportnum); -+ return -EINVAL; -+} -+ -+// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to -+// cast away the const to avoid a compiler warning... -+#define NOCONST(x) ((void *)x) -+ -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) -+{ -+ WARN_ON(!ithc->hid.dev); -+ if (!ithc->hid.dev) -+ return; -+ -+ switch (d->type) { -+ -+ case ITHC_DATA_IGNORE: -+ return; -+ -+ case ITHC_DATA_ERROR: -+ CHECK(ithc_reset, ithc); -+ return; -+ -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ // Response to the report descriptor request sent by ithc_hid_parse(). -+ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); -+ WRITE_ONCE(ithc->hid.parse_done, true); -+ wake_up(&ithc->hid.wait_parse); -+ return; -+ -+ case ITHC_DATA_INPUT_REPORT: -+ { -+ // Standard HID input report. -+ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); -+ if (r < 0) { -+ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", -+ r, d->size, d->size ? *(u8 *)d->data : 0); -+ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, -+ d->data, min(d->size, 0x400u), 0); -+ } -+ return; -+ } -+ -+ case ITHC_DATA_GET_FEATURE: -+ { -+ // Response to a 'get feature' request sent by ithc_hid_raw_request(). -+ bool done = false; -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ if (ithc->hid.get_feature_buf) { -+ if (d->size < ithc->hid.get_feature_size) -+ ithc->hid.get_feature_size = d->size; -+ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); -+ ithc->hid.get_feature_buf = NULL; -+ done = true; -+ } -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ if (done) { -+ wake_up(&ithc->hid.wait_get_feature); -+ } else { -+ // Received data without a matching request, or the request already -+ // timed out. (XXX What's the correct thing to do here?) -+ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, -+ NOCONST(d->data), d->size, 1); -+ } -+ return; -+ } -+ -+ default: -+ pci_err(ithc->pci, "unhandled data type %i\n", d->type); -+ return; -+ } -+} -+ -+static struct hid_ll_driver ithc_ll_driver = { -+ .start = ithc_hid_start, -+ .stop = ithc_hid_stop, -+ .open = ithc_hid_open, -+ .close = ithc_hid_close, -+ .parse = ithc_hid_parse, -+ .raw_request = ithc_hid_raw_request, -+}; -+ -+static void ithc_hid_devres_release(struct device *dev, void *res) -+{ -+ struct hid_device **hidm = res; -+ if (*hidm) -+ hid_destroy_device(*hidm); -+} -+ -+int ithc_hid_init(struct ithc *ithc) -+{ -+ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -+ if (!hidm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, hidm); -+ struct hid_device *hid = hid_allocate_device(); -+ if (IS_ERR(hid)) -+ return PTR_ERR(hid); -+ *hidm = hid; -+ -+ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -+ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -+ hid->ll_driver = &ithc_ll_driver; -+ hid->bus = BUS_PCI; -+ hid->vendor = ithc->vendor_id; -+ hid->product = ithc->product_id; -+ hid->version = 0x100; -+ hid->dev.parent = &ithc->pci->dev; -+ hid->driver_data = ithc; -+ -+ ithc->hid.dev = hid; -+ -+ init_waitqueue_head(&ithc->hid.wait_parse); -+ init_waitqueue_head(&ithc->hid.wait_get_feature); -+ mutex_init(&ithc->hid.get_feature_mutex); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h -new file mode 100644 -index 000000000000..599eb912c8c8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+enum ithc_data_type { -+ ITHC_DATA_IGNORE, -+ ITHC_DATA_RAW, -+ ITHC_DATA_ERROR, -+ ITHC_DATA_REPORT_DESCRIPTOR, -+ ITHC_DATA_INPUT_REPORT, -+ ITHC_DATA_OUTPUT_REPORT, -+ ITHC_DATA_GET_FEATURE, -+ ITHC_DATA_SET_FEATURE, -+}; -+ -+struct ithc_data { -+ enum ithc_data_type type; -+ u32 size; -+ const void *data; -+}; -+ -+struct ithc_hid { -+ struct hid_device *dev; -+ bool parse_done; -+ wait_queue_head_t wait_parse; -+ wait_queue_head_t wait_get_feature; -+ struct mutex get_feature_mutex; -+ void *get_feature_buf; -+ size_t get_feature_size; -+}; -+ -+int ithc_hid_init(struct ithc *ithc); -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); -+ -diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c -new file mode 100644 -index 000000000000..8883987fb352 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.c -@@ -0,0 +1,254 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) -+#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) -+ -+#define DEVCFG_TOUCH_MASK 0x3f -+#define DEVCFG_TOUCH_ENABLE BIT(0) -+#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) -+#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) -+#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) -+#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) -+ -+#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" -+ -+#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) -+#define DEVCFG_SPI_CLKDIV_8 BIT(4) -+#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) -+#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) -+#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) -+#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) -+#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) -+#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat -+#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) -+#define DEVCFG_SPI_UNKNOWN_25 BIT(25) -+#define DEVCFG_SPI_UNKNOWN_26 BIT(26) -+#define DEVCFG_SPI_UNKNOWN_27 BIT(27) -+#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this -+#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? -+ -+struct ithc_device_config { // (Example values are from an SP7+.) -+ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) -+ u32 error; // 04 = 0x00000000 -+ u32 dma_buf_sizes; // 08 = 0x000a00ff -+ u32 touch_cfg; // 0c = 0x0000001c -+ u32 touch_state; // 10 = 0x0000001c -+ u32 device_id; // 14 = 0x43495424 = "$TIC" -+ u32 spi_config; // 18 = 0xfda00a2e -+ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. -+ u16 product_id; // 1e = 0x0c1a -+ u32 revision; // 20 = 0x00000001 -+ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) -+ u32 command; // 28 = 0x00000000 -+ u32 fw_mode; // 2c = 0x00000000 (for fw update?) -+ u32 _unknown_30; // 30 = 0x00000000 -+ u8 eds_minor_ver; // 34 = 0x5e -+ u8 eds_major_ver; // 35 = 0x03 -+ u8 interface_rev; // 36 = 0x04 -+ u8 eu_kernel_ver; // 37 = 0x04 -+ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) -+ u32 _unknown_3c; // 3c = 0x00000002 -+}; -+static_assert(sizeof(struct ithc_device_config) == 64); -+ -+#define RX_CODE_INPUT_REPORT 3 -+#define RX_CODE_FEATURE_REPORT 4 -+#define RX_CODE_REPORT_DESCRIPTOR 5 -+#define RX_CODE_RESET 7 -+ -+#define TX_CODE_SET_FEATURE 3 -+#define TX_CODE_GET_FEATURE 4 -+#define TX_CODE_OUTPUT_REPORT 5 -+#define TX_CODE_GET_REPORT_DESCRIPTOR 7 -+ -+static int ithc_set_device_enabled(struct ithc *ithc, bool enable) -+{ -+ u32 x = ithc->legacy_touch_cfg = -+ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | -+ DEVCFG_TOUCH_HID_REPORT_ENABLE | -+ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); -+ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -+ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); -+} -+ -+int ithc_legacy_init(struct ithc *ithc) -+{ -+ // Since we don't yet know which SPI config the device wants, use default speed and mode -+ // initially for reading config data. -+ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); -+ -+ // Setting the following bit seems to make reading the config more reliable. -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ // Setting this bit may be necessary on ADL devices. -+ switch (ithc->pci->device) { -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); -+ break; -+ } -+ -+ // Take the touch device out of reset. -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -+ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) -+ break; -+ if (retries > 5) { -+ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", -+ readl(&ithc->regs->irq_cause)); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ if (msleep_interruptible(1000)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ -+ // Read configuration data. -+ u32 spi_cfg; -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ struct ithc_device_config config = { 0 }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); -+ u32 *p = (void *)&config; -+ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { -+ spi_cfg = config.spi_config; -+ ithc->vendor_id = config.vendor_id; -+ ithc->product_id = config.product_id; -+ ithc->product_rev = config.revision; -+ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); -+ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); -+ ithc->legacy_touch_cfg = config.touch_cfg; -+ ithc->have_config = true; -+ break; -+ } -+ if (retries > 10) { -+ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -+ config.device_id); -+ return -EIO; -+ } -+ pci_warn(ithc->pci, "failed to read config, retrying\n"); -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ // Apply SPI config and enable touch device. -+ CHECK_RET(ithc_set_spi_config, ithc, -+ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, -+ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : -+ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : -+ SPI_MODE_SINGLE, -+ SPI_MODE_SINGLE); -+ CHECK_RET(ithc_set_device_enabled, ithc, true); -+ ithc_log_regs(ithc); -+ return 0; -+} -+ -+void ithc_legacy_exit(struct ithc *ithc) -+{ -+ CHECK(ithc_set_device_enabled, ithc, false); -+} -+ -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct { -+ u32 code; -+ u32 data_size; -+ u32 _unknown[14]; -+ } *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // Note: RX data is not padded, even though TX data must be padded. -+ if (len != sizeof(*hdr) + hdr->data_size) -+ return -EMSGSIZE; -+ -+ dest->data = hdr + 1; -+ dest->size = hdr->data_size; -+ -+ switch (hdr->code) { -+ case RX_CODE_RESET: -+ // The THC sends a reset request when we need to reinitialize the device. -+ // This usually only happens if we send an invalid command or put the device -+ // in a bad state. -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case RX_CODE_REPORT_DESCRIPTOR: -+ // The descriptor is preceded by 8 nul bytes. -+ if (hdr->data_size < 8) -+ return -ENODATA; -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = (char *)(hdr + 1) + 8; -+ dest->size = hdr->data_size - 8; -+ return 0; -+ case RX_CODE_INPUT_REPORT: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ return 0; -+ case RX_CODE_FEATURE_REPORT: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct { -+ u32 code; -+ u32 data_size; -+ } *hdr = dest; -+ -+ size_t src_size = src->size; -+ const void *src_data = src->data; -+ const u64 get_report_desc_data = 0; -+ u32 code; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ code = TX_CODE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ code = TX_CODE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ code = TX_CODE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ code = TX_CODE_GET_REPORT_DESCRIPTOR; -+ src_size = sizeof(get_report_desc_data); -+ src_data = &get_report_desc_data; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->code = code; -+ hdr->data_size = src_size; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h -new file mode 100644 -index 000000000000..28d692462072 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.h -@@ -0,0 +1,8 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+int ithc_legacy_init(struct ithc *ithc); -+void ithc_legacy_exit(struct ithc *ithc); -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -new file mode 100644 -index 000000000000..ac56c253674b ---- /dev/null -+++ b/drivers/hid/ithc/ithc-main.c -@@ -0,0 +1,431 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+MODULE_DESCRIPTION("Intel Touch Host Controller driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+ -+static const struct pci_device_id ithc_pci_tbl[] = { -+ { -+ .vendor = PCI_VENDOR_ID_INTEL, -+ .device = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subdevice = PCI_ANY_ID, -+ .class = PCI_CLASS_INPUT_PEN << 8, -+ .class_mask = ~0, -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); -+ -+// Module parameters -+ -+static bool ithc_use_polling = false; -+module_param_named(poll, ithc_use_polling, bool, 0); -+MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); -+ -+// Since all known devices seem to use only channel 1, by default we disable channel 0. -+static bool ithc_use_rx0 = false; -+module_param_named(rx0, ithc_use_rx0, bool, 0); -+MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); -+ -+static bool ithc_use_rx1 = true; -+module_param_named(rx1, ithc_use_rx1, bool, 0); -+MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); -+ -+static int ithc_active_ltr_us = -1; -+module_param_named(activeltr, ithc_active_ltr_us, int, 0); -+MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); -+ -+static int ithc_idle_ltr_us = -1; -+module_param_named(idleltr, ithc_idle_ltr_us, int, 0); -+MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); -+ -+static unsigned int ithc_idle_delay_ms = 1000; -+module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); -+MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); -+ -+static bool ithc_log_regs_enabled = false; -+module_param_named(logregs, ithc_log_regs_enabled, bool, 0); -+MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); -+ -+// Interrupts/polling -+ -+static void ithc_disable_interrupts(struct ithc *ithc) -+{ -+ writel(0, &ithc->regs->error_control); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); -+} -+ -+static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) -+{ -+ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, -+ &ithc->regs->dma_rx[channel].status); -+} -+ -+static void ithc_clear_interrupts(struct ithc *ithc) -+{ -+ writel(0xffffffff, &ithc->regs->error_flags); -+ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, -+ &ithc->regs->dma_tx.status); -+} -+ -+static void ithc_idle_timer_callback(struct timer_list *t) -+{ -+ struct ithc *ithc = container_of(t, struct ithc, idle_timer); -+ ithc_set_ltr_idle(ithc); -+} -+ -+static void ithc_process(struct ithc *ithc) -+{ -+ ithc_log_regs(ithc); -+ -+ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. -+ // It does not appear to automatically go back to idle, so we switch it back after a delay. -+ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); -+ -+ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ -+ // Read and clear error bits -+ u32 err = readl(&ithc->regs->error_flags); -+ if (err) { -+ writel(err, &ithc->regs->error_flags); -+ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "error flags: 0x%08x\n", err); -+ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); -+ } -+ -+ // Process DMA rx -+ if (ithc_use_rx0) { -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ if (rx0) -+ ithc_dma_rx(ithc, 0); -+ } -+ if (ithc_use_rx1) { -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ if (rx1) -+ ithc_dma_rx(ithc, 1); -+ } -+ -+ ithc_log_regs(ithc); -+} -+ -+static irqreturn_t ithc_interrupt_thread(int irq, void *arg) -+{ -+ struct ithc *ithc = arg; -+ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", -+ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), -+ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), -+ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), -+ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), -+ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); -+ ithc_process(ithc); -+ return IRQ_HANDLED; -+} -+ -+static int ithc_poll_thread(void *arg) -+{ -+ struct ithc *ithc = arg; -+ unsigned int sleep = 100; -+ while (!kthread_should_stop()) { -+ u32 n = ithc->dma_rx[1].num_received; -+ ithc_process(ithc); -+ // Decrease polling interval to 20ms if we received data, otherwise slowly -+ // increase it up to 200ms. -+ sleep = n != ithc->dma_rx[1].num_received ? 20 -+ : min(200u, sleep + (sleep >> 4) + 1); -+ msleep_interruptible(sleep); -+ } -+ return 0; -+} -+ -+// Device initialization and shutdown -+ -+static void ithc_disable(struct ithc *ithc) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); -+ ithc_disable_interrupts(ithc); -+ ithc_clear_interrupts(ithc); -+} -+ -+static int ithc_init_device(struct ithc *ithc) -+{ -+ // Read ACPI config for QuickSPI mode -+ struct ithc_acpi_config cfg = { 0 }; -+ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); -+ if (!cfg.has_config) -+ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); -+ else -+ ithc_print_acpi_config(ithc, &cfg); -+ ithc->use_quickspi = cfg.has_config; -+ -+ // Shut down device -+ ithc_log_regs(ithc); -+ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; -+ ithc_disable(ithc); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); -+ ithc_log_regs(ithc); -+ -+ // If the device was previously enabled, wait a bit to make sure it's fully shut down. -+ if (was_enabled) -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ -+ // Set Latency Tolerance Reporting config. The device will automatically -+ // apply these values depending on whether it is active or idle. -+ // If active value is too high, DMA buffer data can become truncated. -+ // By default, we set the active LTR value to 50us, and idle to 100ms. -+ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 -+ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 -+ : 50 * 1000; -+ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 -+ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 -+ : 100 * 1000 * 1000; -+ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); -+ -+ if (ithc->use_quickspi) -+ CHECK_RET(ithc_quickspi_init, ithc, &cfg); -+ else -+ CHECK_RET(ithc_legacy_init, ithc); -+ -+ return 0; -+} -+ -+int ithc_reset(struct ithc *ithc) -+{ -+ // FIXME This should probably do devres_release_group()+ithc_start(). -+ // But because this is called during DMA processing, that would have to be done -+ // asynchronously (schedule_work()?). And with extra locking? -+ pci_err(ithc->pci, "reset\n"); -+ CHECK(ithc_init_device, ithc); -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "reset completed\n"); -+ return 0; -+} -+ -+static void ithc_stop(void *res) -+{ -+ struct ithc *ithc = res; -+ pci_dbg(ithc->pci, "stopping\n"); -+ ithc_log_regs(ithc); -+ -+ if (ithc->poll_thread) -+ CHECK(kthread_stop, ithc->poll_thread); -+ if (ithc->irq >= 0) -+ disable_irq(ithc->irq); -+ if (ithc->use_quickspi) -+ ithc_quickspi_exit(ithc); -+ else -+ ithc_legacy_exit(ithc); -+ ithc_disable(ithc); -+ del_timer_sync(&ithc->idle_timer); -+ -+ // Clear DMA config. -+ for (unsigned int i = 0; i < 2; i++) { -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); -+ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); -+ writeb(0, &ithc->regs->dma_rx[i].num_bufs); -+ writeb(0, &ithc->regs->dma_rx[i].num_prds); -+ } -+ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); -+ writeb(0, &ithc->regs->dma_tx.num_prds); -+ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "stopped\n"); -+} -+ -+static void ithc_clear_drvdata(void *res) -+{ -+ struct pci_dev *pci = res; -+ pci_set_drvdata(pci, NULL); -+} -+ -+static int ithc_start(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "starting\n"); -+ if (pci_get_drvdata(pci)) { -+ pci_err(pci, "device already initialized\n"); -+ return -EINVAL; -+ } -+ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) -+ return -ENOMEM; -+ -+ // Allocate/init main driver struct. -+ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); -+ if (!ithc) -+ return -ENOMEM; -+ ithc->irq = -1; -+ ithc->pci = pci; -+ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); -+ pci_set_drvdata(pci, ithc); -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); -+ if (ithc_log_regs_enabled) -+ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); -+ -+ // PCI initialization. -+ CHECK_RET(pcim_enable_device, pci); -+ pci_set_master(pci); -+ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); -+ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); -+ CHECK_RET(pci_set_power_state, pci, PCI_D0); -+ ithc->regs = pcim_iomap_table(pci)[0]; -+ -+ // Allocate IRQ. -+ if (!ithc_use_polling) { -+ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); -+ ithc->irq = CHECK(pci_irq_vector, pci, 0); -+ if (ithc->irq < 0) -+ return ithc->irq; -+ } -+ -+ // Initialize THC and touch device. -+ CHECK_RET(ithc_init_device, ithc); -+ -+ // Initialize HID and DMA. -+ CHECK_RET(ithc_hid_init, ithc); -+ if (ithc_use_rx0) -+ CHECK_RET(ithc_dma_rx_init, ithc, 0); -+ if (ithc_use_rx1) -+ CHECK_RET(ithc_dma_rx_init, ithc, 1); -+ CHECK_RET(ithc_dma_tx_init, ithc); -+ -+ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); -+ -+ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are -+ // disabled BEFORE the buffers are freed. -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); -+ -+ // Start polling/IRQ. -+ if (ithc_use_polling) { -+ pci_info(pci, "using polling instead of irq\n"); -+ // Use a thread instead of simple timer because we want to be able to sleep. -+ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); -+ if (IS_ERR(ithc->poll_thread)) { -+ int err = PTR_ERR(ithc->poll_thread); -+ ithc->poll_thread = NULL; -+ return err; -+ } -+ } else { -+ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, -+ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); -+ } -+ -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ -+ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, -+ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. -+ CHECK_RET(hid_add_device, ithc->hid.dev); -+ -+ CHECK(ithc_debug_init_device, ithc); -+ -+ ithc_set_ltr_idle(ithc); -+ -+ pci_dbg(pci, "started\n"); -+ return 0; -+} -+ -+static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) -+{ -+ pci_dbg(pci, "device probe\n"); -+ return ithc_start(pci); -+} -+ -+static void ithc_remove(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "device remove\n"); -+ // all cleanup is handled by devres -+} -+ -+// For suspend/resume, we just deinitialize and reinitialize everything. -+// TODO It might be cleaner to keep the HID device around, however we would then have to signal -+// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set -+// feature' requests. Hidraw does not seem to have a facility to do that. -+static int ithc_suspend(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm suspend\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_resume(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm resume\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_freeze(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm freeze\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_thaw(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm thaw\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_restore(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm restore\n"); -+ return ithc_start(pci); -+} -+ -+static struct pci_driver ithc_driver = { -+ .name = DEVNAME, -+ .id_table = ithc_pci_tbl, -+ .probe = ithc_probe, -+ .remove = ithc_remove, -+ .driver.pm = &(const struct dev_pm_ops) { -+ .suspend = ithc_suspend, -+ .resume = ithc_resume, -+ .freeze = ithc_freeze, -+ .thaw = ithc_thaw, -+ .restore = ithc_restore, -+ }, -+ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, -+}; -+ -+static int __init ithc_init(void) -+{ -+ ithc_debug_init_module(); -+ return pci_register_driver(&ithc_driver); -+} -+ -+static void __exit ithc_exit(void) -+{ -+ pci_unregister_driver(&ithc_driver); -+ ithc_debug_exit_module(); -+} -+ -+module_init(ithc_init); -+module_exit(ithc_exit); -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c -new file mode 100644 -index 000000000000..e2d1690b8cf8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.c -@@ -0,0 +1,607 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+// Some public THC/QuickSPI documentation can be found in: -+// - Intel Firmware Support Package repo: https://github.com/intel/FSP -+// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 -+ -+#include "ithc.h" -+ -+static const guid_t guid_hidspi = -+ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); -+static const guid_t guid_thc_quickspi = -+ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); -+static const guid_t guid_thc_ltr = -+ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); -+ -+// TODO The HIDSPI spec says revision should be 3. Should we try both? -+#define DSM_REV 2 -+ -+struct hidspi_header { -+ u8 type; -+ u16 len; -+ u8 id; -+} __packed; -+static_assert(sizeof(struct hidspi_header) == 4); -+ -+#define HIDSPI_INPUT_TYPE_DATA 1 -+#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 -+#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 -+#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 -+#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 -+#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 -+#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 -+#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 -+#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 -+ -+#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 -+#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 -+#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 -+#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 -+#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 -+#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 -+#define HIDSPI_OUTPUT_TYPE_COMMAND 7 -+ -+struct hidspi_device_descriptor { -+ u16 wDeviceDescLength; -+ u16 bcdVersion; -+ u16 wReportDescLength; -+ u16 wMaxInputLength; -+ u16 wMaxOutputLength; -+ u16 wMaxFragmentLength; -+ u16 wVendorID; -+ u16 wProductID; -+ u16 wVersionID; -+ u16 wFlags; -+ u32 dwReserved; -+}; -+static_assert(sizeof(struct hidspi_device_descriptor) == 24); -+ -+static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_INTEGER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); -+ *dest = (u32)o->integer.value; -+ ACPI_FREE(o); -+ return 1; -+} -+ -+static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_BUFFER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ if (o->buffer.length != len) { -+ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", -+ guid, func, o->buffer.length, len); -+ ACPI_FREE(o); -+ return -1; -+ } -+ memcpy(dest, o->buffer.pointer, len); -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); -+ ACPI_FREE(o); -+ return 1; -+} -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) -+{ -+ int r; -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ -+ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); -+ if (!cfg->has_config) -+ return 0; -+ -+ // HIDSPI settings -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_header_address = r > 0; -+ if (r > 0 && cfg->input_report_header_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", -+ cfg->input_report_header_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_body_address = r > 0; -+ if (r > 0 && cfg->input_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", -+ cfg->input_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_output_report_body_address = r > 0; -+ if (r > 0 && cfg->output_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", -+ cfg->output_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_read_opcode = r > 0; -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_write_opcode = r > 0; -+ -+ u32 flags; -+ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); -+ if (r < 0) -+ return r; -+ cfg->has_read_mode = cfg->has_write_mode = r > 0; -+ if (r > 0) { -+ cfg->read_mode = (flags >> 14) & 3; -+ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; -+ } -+ -+ // Quick SPI settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); -+ if (r < 0) -+ return r; -+ cfg->has_spi_frequency = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); -+ if (r < 0) -+ return r; -+ cfg->has_limit_packet_size = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); -+ if (r < 0) -+ return r; -+ cfg->has_tx_delay = r > 0; -+ if (r > 0) -+ cfg->tx_delay &= 0xffff; -+ -+ // LTR settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_active_ltr = r > 0; -+ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { -+ if (cfg->active_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", -+ cfg->active_ltr); -+ cfg->active_ltr = 500; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_idle_ltr = r > 0; -+ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { -+ if (cfg->idle_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", -+ cfg->idle_ltr); -+ cfg->idle_ltr = 500; -+ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) -+ cfg->idle_ltr = cfg->active_ltr; -+ } -+ -+ return 0; -+} -+ -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ if (!cfg->has_config) { -+ pci_info(ithc->pci, "No ACPI config"); -+ return; -+ } -+ -+ char input_report_header_address[16] = "-"; -+ if (cfg->has_input_report_header_address) -+ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); -+ char input_report_body_address[16] = "-"; -+ if (cfg->has_input_report_body_address) -+ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); -+ char output_report_body_address[16] = "-"; -+ if (cfg->has_output_report_body_address) -+ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); -+ char read_opcode[16] = "-"; -+ if (cfg->has_read_opcode) -+ sprintf(read_opcode, "0x%02x", cfg->read_opcode); -+ char write_opcode[16] = "-"; -+ if (cfg->has_write_opcode) -+ sprintf(write_opcode, "0x%02x", cfg->write_opcode); -+ char read_mode[16] = "-"; -+ if (cfg->has_read_mode) -+ sprintf(read_mode, "%i", cfg->read_mode); -+ char write_mode[16] = "-"; -+ if (cfg->has_write_mode) -+ sprintf(write_mode, "%i", cfg->write_mode); -+ char spi_frequency[16] = "-"; -+ if (cfg->has_spi_frequency) -+ sprintf(spi_frequency, "%u", cfg->spi_frequency); -+ char limit_packet_size[16] = "-"; -+ if (cfg->has_limit_packet_size) -+ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); -+ char tx_delay[16] = "-"; -+ if (cfg->has_tx_delay) -+ sprintf(tx_delay, "%u", cfg->tx_delay); -+ char active_ltr[16] = "-"; -+ if (cfg->has_active_ltr) -+ sprintf(active_ltr, "%u", cfg->active_ltr); -+ char idle_ltr[16] = "-"; -+ if (cfg->has_idle_ltr) -+ sprintf(idle_ltr, "%u", cfg->idle_ltr); -+ -+ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", -+ input_report_header_address, input_report_body_address, output_report_body_address, -+ read_opcode, write_opcode, read_mode, write_mode, -+ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); -+} -+ -+static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) -+{ -+ writeb(opcode, &ithc->regs->opcode[i].header); -+ writeb(opcode, &ithc->regs->opcode[i].single); -+ writeb(opcode, &ithc->regs->opcode[i].dual); -+ writeb(opcode, &ithc->regs->opcode[i].quad); -+} -+ -+static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); -+ -+ // SPI frequency and mode -+ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { -+ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); -+ return -EINVAL; -+ } -+ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); -+ bool clkdiv8 = clkdiv > 7; -+ if (clkdiv8) -+ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); -+ if (!clkdiv) -+ clkdiv = 1; -+ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, -+ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, -+ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); -+ -+ // SPI addresses and opcodes -+ if (cfg->has_input_report_header_address) -+ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); -+ if (cfg->has_input_report_body_address) { -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); -+ } -+ if (cfg->has_output_report_body_address) -+ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); -+ -+ switch (ithc->pci->device) { -+ // LKF/TGL don't support QuickSPI. -+ // For ADL, opcode layout is RX/TX/unused. -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ if (cfg->has_read_opcode) { -+ set_opcode(ithc, 0, cfg->read_opcode); -+ } -+ if (cfg->has_write_opcode) { -+ set_opcode(ithc, 1, cfg->write_opcode); -+ } -+ break; -+ // For MTL, opcode layout was changed to RX/RX/TX. -+ // (RPL layout is unknown.) -+ default: -+ if (cfg->has_read_opcode) { -+ set_opcode(ithc, 0, cfg->read_opcode); -+ set_opcode(ithc, 1, cfg->read_opcode); -+ } -+ if (cfg->has_write_opcode) { -+ set_opcode(ithc, 2, cfg->write_opcode); -+ } -+ break; -+ } -+ -+ ithc_log_regs(ithc); -+ -+ // The rest... -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), -+ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); -+ -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), -+ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(2)); -+ -+ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), -+ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); -+ -+ bitsl_set(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); -+ -+ return 0; -+} -+ -+static int wait_for_report(struct ithc *ithc) -+{ -+ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, -+ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); -+ -+ u32 h = readl(&ithc->regs->input_header); -+ ithc_log_regs(ithc); -+ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE -+ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { -+ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); -+ return -ENODATA; -+ } -+ return INPUT_HEADER_REPORT_LENGTH(h) * 4; -+} -+ -+static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing HIDSPI\n"); -+ -+ // HIDSPI initialization sequence: -+ // "1. The host shall invoke the ACPI reset method to clear the device state." -+ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); -+ if (ACPI_FAILURE(s)) { -+ pci_err(ithc->pci, "ACPI reset failed\n"); -+ return -EIO; -+ } -+ -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ -+ // "2. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing a device reset response." -+ int size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(struct hidspi_header)) { -+ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "3. The host shall read the reset response from the device at the Input Report addresses -+ // specified in ACPI." -+ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; -+ struct { -+ struct hidspi_header header; -+ union { -+ struct hidspi_device_descriptor device_desc; -+ u32 data[16]; -+ }; -+ } resp = { 0 }; -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { -+ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); -+ return -ENOMSG; -+ } -+ -+ // "4. The host shall then write an Output Report to the device at the Output Report Address -+ // specified in ACPI, requesting the Device Descriptor from the device." -+ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; -+ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); -+ -+ // "5. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing the Device Descriptor." -+ size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { -+ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "6. The host shall read the Device Descriptor from the Input Report addresses specified -+ // in ACPI." -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ memset(&resp, 0, sizeof(resp)); -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { -+ pci_err(ithc->pci, "received type %i instead of device descriptor\n", -+ resp.header.type); -+ return -ENOMSG; -+ } -+ struct hidspi_device_descriptor *d = &resp.device_desc; -+ if (resp.header.len < sizeof(*d)) { -+ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", -+ resp.header.len); -+ return -EMSGSIZE; -+ } -+ if (d->wDeviceDescLength != sizeof(*d)) { -+ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", -+ d->wDeviceDescLength); -+ return -EMSGSIZE; -+ } -+ -+ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", -+ d->bcdVersion, d->wReportDescLength, -+ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, -+ d->wVendorID, d->wProductID, d->wVersionID, -+ d->wFlags, d->dwReserved); -+ -+ ithc->vendor_id = d->wVendorID; -+ ithc->product_id = d->wProductID; -+ ithc->product_rev = d->wVersionID; -+ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, -+ d->wReportDescLength + sizeof(struct hidspi_header)); -+ ithc->max_tx_size = d->wMaxOutputLength; -+ ithc->have_config = true; -+ -+ // "7. The device and host shall then enter their "Ready" states - where the device may -+ // begin sending Input Reports, and the device shall be prepared for Output Reports from -+ // the host." -+ -+ return 0; -+} -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); -+ ithc_log_regs(ithc); -+ -+ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, -+ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); -+ -+ // TODO Do we need to set any of the following bits here? -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); -+ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ ithc_log_regs(ithc); -+ -+ return 0; -+} -+ -+void ithc_quickspi_exit(struct ithc *ithc) -+{ -+ // TODO Should we send HIDSPI 'power off' command? -+ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; -+ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; -+ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() -+} -+ -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct hidspi_header *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // TODO Do we need to handle HIDSPI packet fragmentation? -+ if (len < sizeof(*hdr) + hdr->len) -+ return -EMSGSIZE; -+ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) -+ return -EMSGSIZE; -+ -+ switch (hdr->type) { -+ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: -+ // TODO "When the device detects an error condition, it may interrupt and make -+ // available to the host an Input Report containing an unsolicited Reset Response. -+ // After receiving an unsolicited Reset Response, the host shall initiate the -+ // request procedure from step (4) in the [HIDSPI initialization] process." -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = hdr + 1; -+ dest->size = hdr->len; -+ return 0; -+ case HIDSPI_INPUT_TYPE_DATA: -+ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: -+ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_IGNORE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct hidspi_header *hdr = dest; -+ -+ size_t src_size = src->size; -+ const u8 *src_data = src->data; -+ u8 type; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; -+ src_size = 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ u8 id = 0; -+ if (src_size) { -+ id = *src_data++; -+ src_size--; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->type = type; -+ hdr->len = (u16)src_size; -+ hdr->id = id; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h -new file mode 100644 -index 000000000000..74d882f6b2f0 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.h -@@ -0,0 +1,39 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+struct ithc_acpi_config { -+ bool has_config: 1; -+ bool has_input_report_header_address: 1; -+ bool has_input_report_body_address: 1; -+ bool has_output_report_body_address: 1; -+ bool has_read_opcode: 1; -+ bool has_write_opcode: 1; -+ bool has_read_mode: 1; -+ bool has_write_mode: 1; -+ bool has_spi_frequency: 1; -+ bool has_limit_packet_size: 1; -+ bool has_tx_delay: 1; -+ bool has_active_ltr: 1; -+ bool has_idle_ltr: 1; -+ u32 input_report_header_address; -+ u32 input_report_body_address; -+ u32 output_report_body_address; -+ u8 read_opcode; -+ u8 write_opcode; -+ u8 read_mode; -+ u8 write_mode; -+ u32 spi_frequency; -+ u32 limit_packet_size; -+ u32 tx_delay; // us/10 // TODO use? -+ u32 active_ltr; // ns/1024 -+ u32 idle_ltr; // ns/1024 -+}; -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+void ithc_quickspi_exit(struct ithc *ithc); -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c -new file mode 100644 -index 000000000000..c0f13506af20 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.c -@@ -0,0 +1,154 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writel((readl(reg) & ~mask) | (val & mask), reg); -+} -+ -+void bitsb(__iomem u8 *reg, u8 mask, u8 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writeb((readb(reg) & ~mask) | (val & mask), reg); -+} -+ -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) -+{ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ u32 x; -+ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) -+{ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ u8 x; -+ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) -+{ -+ unsigned int s = 0; -+ u64 v = *ns; -+ while (v > 0x3ff) { -+ s++; -+ v >>= 5; -+ } -+ if (s > 5) { -+ s = 5; -+ v = 0x3ff; -+ } -+ *val = v; -+ *scale = s; -+ *ns = v << (5 * s); -+} -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) -+{ -+ unsigned int active_val, active_scale, idle_val, idle_scale; -+ calc_ltr(&active_ltr_ns, &active_val, &active_scale); -+ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); -+ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", -+ active_ltr_ns, idle_ltr_ns); -+ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | -+ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | -+ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), -+ &ithc->regs->ltr_config); -+} -+ -+void ithc_set_ltr_idle(struct ithc *ithc) -+{ -+ u32 ltr = readl(&ithc->regs->ltr_config); -+ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { -+ case LTR_CONFIG_STATUS_IDLE: -+ break; -+ case LTR_CONFIG_STATUS_ACTIVE: -+ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); -+ break; -+ default: -+ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); -+ break; -+ } -+} -+ -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) -+{ -+ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) -+ return -EINVAL; -+ static const char * const modes[] = { "single", "dual", "quad" }; -+ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", -+ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), -+ modes[read_mode], modes[write_mode]); -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | -+ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | -+ SPI_CONFIG_CLKDIV_8, -+ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | -+ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | -+ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); -+ return 0; -+} -+ -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) -+{ -+ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); -+ if (size > sizeof(ithc->regs->spi_cmd.data)) -+ return -EINVAL; -+ -+ // Wait if the device is still busy. -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ // Clear result flags. -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ -+ // Init SPI command data. -+ writeb(command, &ithc->regs->spi_cmd.code); -+ writew(size, &ithc->regs->spi_cmd.size); -+ writel(offset, &ithc->regs->spi_cmd.offset); -+ u32 *p = data, n = (size + 3) / 4; -+ for (u32 i = 0; i < n; i++) -+ writel(p[i], &ithc->regs->spi_cmd.data[i]); -+ -+ // Start transmission. -+ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ -+ // Read response. -+ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) -+ return -EIO; -+ if (readw(&ithc->regs->spi_cmd.size) != size) -+ return -EMSGSIZE; -+ for (u32 i = 0; i < n; i++) -+ p[i] = readl(&ithc->regs->spi_cmd.data[i]); -+ -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h -new file mode 100644 -index 000000000000..4f541fe533fa ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.h -@@ -0,0 +1,211 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) -+#define LTR_CONFIG_TOGGLE BIT(1) -+#define LTR_CONFIG_ENABLE_IDLE BIT(2) -+#define LTR_CONFIG_APPLY BIT(3) -+#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) -+#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) -+#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) -+#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) -+#define LTR_CONFIG_STATUS_ACTIVE BIT(30) -+#define LTR_CONFIG_STATUS_IDLE BIT(31) -+ -+#define CONTROL_QUIESCE BIT(1) -+#define CONTROL_IS_QUIESCED BIT(2) -+#define CONTROL_NRESET BIT(3) -+#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) -+#define CONTROL_READY BIT(29) -+ -+#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) -+#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) -+#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) -+#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) -+#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) -+#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write -+#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) -+ -+#define SPI_CLK_FREQ_BASE 125000000 -+#define SPI_MODE_SINGLE 0 -+#define SPI_MODE_DUAL 1 -+#define SPI_MODE_QUAD 2 -+ -+#define ERROR_CONTROL_UNKNOWN_0 BIT(0) -+#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs -+#define ERROR_CONTROL_UNKNOWN_2 BIT(2) -+#define ERROR_CONTROL_UNKNOWN_3 BIT(3) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? -+#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs -+ -+#define ERROR_STATUS_DMA BIT(28) -+#define ERROR_STATUS_SPI BIT(30) -+ -+#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message -+#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) -+#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) -+#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) -+#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) -+#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) -+#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) -+ -+#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define SPI_CMD_CONTROL_IRQ BIT(1) -+ -+#define SPI_CMD_CODE_READ 4 -+#define SPI_CMD_CODE_WRITE 6 -+ -+#define SPI_CMD_STATUS_DONE BIT(0) -+#define SPI_CMD_STATUS_ERROR BIT(1) -+#define SPI_CMD_STATUS_BUSY BIT(3) -+ -+#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define DMA_TX_CONTROL_IRQ BIT(3) -+ -+#define DMA_TX_STATUS_DONE BIT(0) -+#define DMA_TX_STATUS_ERROR BIT(1) -+#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) -+#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? -+ -+#define INPUT_HEADER_VERSION(x) ((x) & 0xf) -+#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) -+#define INPUT_HEADER_SYNC(x) ((x) >> 24) -+#define INPUT_HEADER_VERSION_VALUE 3 -+#define INPUT_HEADER_SYNC_VALUE 0x5a -+ -+#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) -+#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) -+ -+#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) -+#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) -+#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) -+#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) -+#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) -+#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) -+#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) -+ -+#define DMA_RX_CONTROL_ENABLE BIT(0) -+#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only -+#define DMA_RX_CONTROL_IRQ_DATA BIT(5) -+ -+#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? -+#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? -+#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices -+ -+#define DMA_RX_WRAP_FLAG BIT(7) -+ -+#define DMA_RX_STATUS_ERROR BIT(3) -+#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) -+#define DMA_RX_STATUS_HAVE_DATA BIT(5) -+#define DMA_RX_STATUS_ENABLED BIT(8) -+ -+#define INIT_UNKNOWN_GUC_2 BIT(2) -+#define INIT_UNKNOWN_3 BIT(3) -+#define INIT_UNKNOWN_GUC_4 BIT(4) -+#define INIT_UNKNOWN_5 BIT(5) -+#define INIT_UNKNOWN_31 BIT(31) -+ -+// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. -+#define COUNTER_RESET BIT(31) -+ -+struct ithc_registers { -+ /* 0000 */ u32 _unknown_0000[5]; -+ /* 0014 */ u32 ltr_config; -+ /* 0018 */ u32 _unknown_0018[1018]; -+ /* 1000 */ u32 _unknown_1000; -+ /* 1004 */ u32 _unknown_1004; -+ /* 1008 */ u32 control_bits; -+ /* 100c */ u32 _unknown_100c; -+ /* 1010 */ u32 spi_config; -+ struct { -+ /* 1014/1018/101c */ u8 header; -+ /* 1015/1019/101d */ u8 quad; -+ /* 1016/101a/101e */ u8 dual; -+ /* 1017/101b/101f */ u8 single; -+ } opcode[3]; -+ /* 1020 */ u32 error_control; -+ /* 1024 */ u32 error_status; // write to clear -+ /* 1028 */ u32 error_flags; // write to clear -+ /* 102c */ u32 _unknown_102c[5]; -+ struct { -+ /* 1040 */ u8 control; -+ /* 1041 */ u8 code; -+ /* 1042 */ u16 size; -+ /* 1044 */ u32 status; // write to clear -+ /* 1048 */ u32 offset; -+ /* 104c */ u32 data[16]; -+ /* 108c */ u32 _unknown_108c; -+ } spi_cmd; -+ struct { -+ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1098 */ u8 control; -+ /* 1099 */ u8 _unknown_1099; -+ /* 109a */ u8 _unknown_109a; -+ /* 109b */ u8 num_prds; -+ /* 109c */ u32 status; // write to clear -+ /* 10a0 */ u32 _unknown_10a0[5]; -+ /* 10b4 */ u32 spi_addr; -+ } dma_tx; -+ /* 10b8 */ u32 spi_header_addr; -+ union { -+ /* 10bc */ u32 irq_cause; // in legacy THC mode -+ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) -+ }; -+ /* 10c0 */ u32 _unknown_10c0[8]; -+ /* 10e0 */ u32 _unknown_10e0_counters[3]; -+ /* 10ec */ u32 quickspi_config1; -+ /* 10f0 */ u32 quickspi_config2; -+ /* 10f4 */ u32 _unknown_10f4[3]; -+ struct { -+ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1108/1208 */ u8 num_bufs; -+ /* 1109/1209 */ u8 num_prds; -+ /* 110a/120a */ u16 _unknown_110a; -+ /* 110c/120c */ u8 control; -+ /* 110d/120d */ u8 head; -+ /* 110e/120e */ u8 tail; -+ /* 110f/120f */ u8 control2; -+ /* 1110/1210 */ u32 status; // write to clear -+ /* 1114/1214 */ u32 _unknown_1114; -+ /* 1118/1218 */ u64 _unknown_1118_guc_addr; -+ /* 1120/1220 */ u32 _unknown_1120_guc; -+ /* 1124/1224 */ u32 _unknown_1124_guc; -+ /* 1128/1228 */ u32 init_unknown; -+ /* 112c/122c */ u32 _unknown_112c; -+ /* 1130/1230 */ u64 _unknown_1130_guc_addr; -+ /* 1138/1238 */ u32 _unknown_1138_guc; -+ /* 113c/123c */ u32 _unknown_113c; -+ /* 1140/1240 */ u32 _unknown_1140_guc; -+ /* 1144/1244 */ u32 _unknown_1144[11]; -+ /* 1170/1270 */ u32 spi_addr; -+ /* 1174/1274 */ u32 _unknown_1174[11]; -+ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; -+ /* 11b8/12b8 */ u32 _unknown_11b8[18]; -+ } dma_rx[2]; -+}; -+static_assert(sizeof(struct ithc_registers) == 0x1300); -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val); -+void bitsb(__iomem u8 *reg, u8 mask, u8 val); -+#define bitsl_set(reg, x) bitsl(reg, x, x) -+#define bitsb_set(reg, x) bitsb(reg, x, x) -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); -+void ithc_set_ltr_idle(struct ithc *ithc); -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); -+ -diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h -new file mode 100644 -index 000000000000..aec320d4e945 ---- /dev/null -+++ b/drivers/hid/ithc/ithc.h -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEVNAME "ithc" -+#define DEVFULLNAME "Intel Touch Host Controller" -+ -+#undef pr_fmt -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) -+#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) -+ -+#define NUM_RX_BUF 16 -+ -+// PCI device IDs: -+// Lakefield -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 -+// Tiger Lake -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 -+// Alder Lake -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 -+// Raptor Lake -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 -+// Meteor Lake -+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b -+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b -+ -+struct ithc; -+ -+#include "ithc-regs.h" -+#include "ithc-hid.h" -+#include "ithc-dma.h" -+#include "ithc-legacy.h" -+#include "ithc-quickspi.h" -+#include "ithc-debug.h" -+ -+struct ithc { -+ char phys[32]; -+ struct pci_dev *pci; -+ int irq; -+ struct task_struct *poll_thread; -+ struct timer_list idle_timer; -+ -+ struct ithc_registers __iomem *regs; -+ struct ithc_registers *prev_regs; // for debugging -+ struct ithc_dma_rx dma_rx[2]; -+ struct ithc_dma_tx dma_tx; -+ struct ithc_hid hid; -+ -+ bool use_quickspi; -+ bool have_config; -+ u16 vendor_id; -+ u16 product_id; -+ u32 product_rev; -+ u32 max_rx_size; -+ u32 max_tx_size; -+ u32 legacy_touch_cfg; -+}; -+ -+int ithc_reset(struct ithc *ithc); -+ --- -2.47.1 - diff --git a/patches/6.14-rc2/0007-surface-sam-over-hid.patch b/patches/6.14-rc2/0007-surface-sam-over-hid.patch deleted file mode 100644 index a65acd8e4f..0000000000 --- a/patches/6.14-rc2/0007-surface-sam-over-hid.patch +++ /dev/null @@ -1,308 +0,0 @@ -From 064893f3e33bd77cecece7ea4047b3a6e1147fe2 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 25 Jul 2020 17:19:53 +0200 -Subject: [PATCH] i2c: acpi: Implement RawBytes read access - -Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C -device via a generic serial bus operation region and RawBytes read -access. On the Surface Book 1, this access is required to turn on (and -off) the discrete GPU. - -Multiple things are to note here: - -a) The RawBytes access is device/driver dependent. The ACPI - specification states: - - > Raw accesses assume that the writer has knowledge of the bus that - > the access is made over and the device that is being accessed. The - > protocol may only ensure that the buffer is transmitted to the - > appropriate driver, but the driver must be able to interpret the - > buffer to communicate to a register. - - Thus this implementation may likely not work on other devices - accessing I2C via the RawBytes accessor type. - -b) The MSHW0030 I2C device is an HID-over-I2C device which seems to - serve multiple functions: - - 1. It is the main access point for the legacy-type Surface Aggregator - Module (also referred to as SAM-over-HID, as opposed to the newer - SAM-over-SSH/UART). It has currently not been determined on how - support for the legacy SAM should be implemented. Likely via a - custom HID driver. - - 2. It seems to serve as the HID device for the Integrated Sensor Hub. - This might complicate matters with regards to implementing a - SAM-over-HID driver required by legacy SAM. - -In light of this, the simplest approach has been chosen for now. -However, it may make more sense regarding breakage and compatibility to -either provide functionality for replacing or enhancing the default -operation region handler via some additional API functions, or even to -completely blacklist MSHW0030 from the I2C core and provide a custom -driver for it. - -Replacing/enhancing the default operation region handler would, however, -either require some sort of secondary driver and access point for it, -from which the new API functions would be called and the new handler -(part) would be installed, or hard-coding them via some sort of -quirk-like interface into the I2C core. - -Signed-off-by: Maximilian Luz -Patchset: surface-sam-over-hid ---- - drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index 14ae0cfc325e..6197c5252d2a 100644 ---- a/drivers/i2c/i2c-core-acpi.c -+++ b/drivers/i2c/i2c-core-acpi.c -@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, - return (ret == 1) ? 0 : -EIO; - } - -+static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, -+ u8 *data, u8 data_len) -+{ -+ struct i2c_msg msgs[1]; -+ int ret; -+ -+ msgs[0].addr = client->addr; -+ msgs[0].flags = client->flags; -+ msgs[0].len = data_len + 1; -+ msgs[0].buf = data; -+ -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret < 0) { -+ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* 1 transfer must have completed successfully */ -+ return (ret == 1) ? 0 : -EIO; -+} -+ - static acpi_status - i2c_acpi_space_handler(u32 function, acpi_physical_address command, - u32 bits, u64 *value64, -@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, - } - break; - -+ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: -+ if (action == ACPI_READ) { -+ dev_warn(&adapter->dev, -+ "protocol 0x%02x not supported for client 0x%02x\n", -+ accessor_type, client->addr); -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } else { -+ status = acpi_gsb_i2c_write_raw_bytes(client, -+ gsb->data, info->access_length); -+ } -+ break; -+ - default: - dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", - accessor_type, client->addr); --- -2.47.1 - -From f6714cb9a95aeec3379336df70e7cc8d9537f727 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 13 Feb 2021 16:41:18 +0100 -Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch - -Add driver exposing the discrete GPU power-switch of the Microsoft -Surface Book 1 to user-space. - -On the Surface Book 1, the dGPU power is controlled via the Surface -System Aggregator Module (SAM). The specific SAM-over-HID command for -this is exposed via ACPI. This module provides a simple driver exposing -the ACPI call via a sysfs parameter to user-space, so that users can -easily power-on/-off the dGPU. - -Patchset: surface-sam-over-hid ---- - drivers/platform/surface/Kconfig | 7 + - drivers/platform/surface/Makefile | 1 + - .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ - 3 files changed, 144 insertions(+) - create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c - -diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index b629e82af97c..68656e8f309e 100644 ---- a/drivers/platform/surface/Kconfig -+++ b/drivers/platform/surface/Kconfig -@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH - Select M or Y here, if you want to provide tablet-mode switch input - events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. - -+config SURFACE_BOOK1_DGPU_SWITCH -+ tristate "Surface Book 1 dGPU Switch Driver" -+ depends on SYSFS -+ help -+ This driver provides a sysfs switch to set the power-state of the -+ discrete GPU found on the Microsoft Surface Book 1. -+ - config SURFACE_DTX - tristate "Surface DTX (Detachment System) Driver" - depends on SURFACE_AGGREGATOR -diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 ---- a/drivers/platform/surface/Makefile -+++ b/drivers/platform/surface/Makefile -@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o - obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o - obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o - obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o -+obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o - obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o - obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o - obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o -diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c -new file mode 100644 -index 000000000000..68db237734a1 ---- /dev/null -+++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c -@@ -0,0 +1,136 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include -+#include -+#include -+ -+/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ -+static const guid_t dgpu_sw_guid = -+ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, -+ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); -+ -+#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" -+#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" -+#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" -+ -+static int sb1_dgpu_sw_dsmcall(void) -+{ -+ union acpi_object *obj; -+ acpi_handle handle; -+ acpi_status status; -+ -+ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); -+ if (status) -+ return -EINVAL; -+ -+ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); -+ if (!obj) -+ return -EINVAL; -+ -+ ACPI_FREE(obj); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgon(struct device *dev) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); -+ if (status) { -+ dev_err(dev, "failed to run HGON: %d\n", status); -+ return -EINVAL; -+ } -+ -+ ACPI_FREE(buf.pointer); -+ -+ dev_info(dev, "turned-on dGPU via HGON\n"); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgof(struct device *dev) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); -+ if (status) { -+ dev_err(dev, "failed to run HGOF: %d\n", status); -+ return -EINVAL; -+ } -+ -+ ACPI_FREE(buf.pointer); -+ -+ dev_info(dev, "turned-off dGPU via HGOF\n"); -+ return 0; -+} -+ -+static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool value; -+ int status; -+ -+ status = kstrtobool(buf, &value); -+ if (status < 0) -+ return status; -+ -+ if (!value) -+ return 0; -+ -+ status = sb1_dgpu_sw_dsmcall(); -+ -+ return status < 0 ? status : len; -+} -+static DEVICE_ATTR_WO(dgpu_dsmcall); -+ -+static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool power; -+ int status; -+ -+ status = kstrtobool(buf, &power); -+ if (status < 0) -+ return status; -+ -+ if (power) -+ status = sb1_dgpu_sw_hgon(dev); -+ else -+ status = sb1_dgpu_sw_hgof(dev); -+ -+ return status < 0 ? status : len; -+} -+static DEVICE_ATTR_WO(dgpu_power); -+ -+static struct attribute *sb1_dgpu_sw_attrs[] = { -+ &dev_attr_dgpu_dsmcall.attr, -+ &dev_attr_dgpu_power.attr, -+ NULL -+}; -+ATTRIBUTE_GROUPS(sb1_dgpu_sw); -+ -+/* -+ * The dGPU power seems to be actually handled by MSHW0040. However, that is -+ * also the power-/volume-button device with a mainline driver. So let's use -+ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. -+ */ -+static const struct acpi_device_id sb1_dgpu_sw_match[] = { -+ { "MSHW0041", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); -+ -+static struct platform_driver sb1_dgpu_sw = { -+ .driver = { -+ .name = "surfacebook1_dgpu_switch", -+ .acpi_match_table = sb1_dgpu_sw_match, -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ .dev_groups = sb1_dgpu_sw_groups, -+ }, -+}; -+module_platform_driver(sb1_dgpu_sw); -+ -+MODULE_AUTHOR("Maximilian Luz "); -+MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); -+MODULE_LICENSE("GPL"); --- -2.47.1 - diff --git a/patches/6.14-rc2/0008-surface-button.patch b/patches/6.14-rc2/0008-surface-button.patch deleted file mode 100644 index 934e9156d2..0000000000 --- a/patches/6.14-rc2/0008-surface-button.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 9d06bf6cc92b13c9e4c4781484b82804c4150d80 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Tue, 5 Oct 2021 00:05:09 +1100 -Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices - -The power button on the AMD variant of the Surface Laptop uses the -same MSHW0040 device ID as the 5th and later generation of Surface -devices, however they report 0 for their OEM platform revision. As the -_DSM does not exist on the devices requiring special casing, check for -the existance of the _DSM to determine if soc_button_array should be -loaded. - -Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") -Co-developed-by: Maximilian Luz - -Signed-off-by: Sachi King -Patchset: surface-button ---- - drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- - 1 file changed, 8 insertions(+), 25 deletions(-) - -diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index 5c5d407fe965..4e1bfe90e730 100644 ---- a/drivers/input/misc/soc_button_array.c -+++ b/drivers/input/misc/soc_button_array.c -@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { - * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned - * devices use MSHW0040 for power and volume buttons, however the way they - * have to be addressed differs. Make sure that we only load this drivers -- * for the correct devices by checking the OEM Platform Revision provided by -- * the _DSM method. -+ * for the correct devices by checking if the OEM Platform Revision DSM call -+ * exists. - */ - #define MSHW0040_DSM_REVISION 0x01 - #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision -@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = - static int soc_device_check_MSHW0040(struct device *dev) - { - acpi_handle handle = ACPI_HANDLE(dev); -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, NULL, -- ACPI_TYPE_INTEGER); -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- /* -- * If the revision is zero here, the _DSM evaluation has failed. This -- * indicates that we have a Pro 4 or Book 1 and this driver should not -- * be used. -- */ -- if (oem_platform_rev == 0) -- return -ENODEV; -+ bool exists; - -- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); -+ // check if OEM platform revision DSM call exists -+ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - -- return 0; -+ return exists ? 0 : -ENODEV; - } - - /* --- -2.47.1 - -From f870bb021693abb7ea617c323216c615151b62e1 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Tue, 5 Oct 2021 00:22:57 +1100 -Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd - variant - -The AMD variant of the Surface Laptop report 0 for their OEM platform -revision. The Surface devices that require the surfacepro3_button -driver do not have the _DSM that gets the OEM platform revision. If the -method does not exist, load surfacepro3_button. - -Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") -Co-developed-by: Maximilian Luz - -Signed-off-by: Sachi King -Patchset: surface-button ---- - drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- - 1 file changed, 6 insertions(+), 24 deletions(-) - -diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 ---- a/drivers/platform/surface/surfacepro3_button.c -+++ b/drivers/platform/surface/surfacepro3_button.c -@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) - /* - * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device - * ID (MSHW0040) for the power/volume buttons. Make sure this is the right -- * device by checking for the _DSM method and OEM Platform Revision. -+ * device by checking for the _DSM method and OEM Platform Revision DSM -+ * function. - * - * Returns true if the driver should bind to this device, i.e. the device is - * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. -@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) - static bool surface_button_check_MSHW0040(struct acpi_device *dev) - { - acpi_handle handle = dev->handle; -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, -- NULL, ACPI_TYPE_INTEGER); -- -- /* -- * If evaluating the _DSM fails, the method is not present. This means -- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we -- * should use this driver. We use revision 0 indicating it is -- * unavailable. -- */ -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); - -- return oem_platform_rev == 0; -+ // make sure that OEM platform revision DSM call does not exist -+ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - } - - --- -2.47.1 - diff --git a/patches/6.14-rc2/0009-surface-typecover.patch b/patches/6.14-rc2/0009-surface-typecover.patch deleted file mode 100644 index 7cc1b3eb95..0000000000 --- a/patches/6.14-rc2/0009-surface-typecover.patch +++ /dev/null @@ -1,575 +0,0 @@ -From df8f9981df6f0a92100266397ded155314efc7e3 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 18 Feb 2023 01:02:49 +0100 -Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 - Type-Cover - -The touchpad on the Type-Cover of the Surface Go 3 is sometimes not -being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this -issue. - -More specifically, the device in question is a fairly standard modern -touchpad with pointer and touchpad input modes. During setup, the device -needs to be switched from pointer- to touchpad-mode (which is done in -hid-multitouch) to fully utilize it as intended. Unfortunately, however, -this seems to occasionally fail silently, leaving the device in -pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. - -Link: https://github.com/linux-surface/linux-surface/issues/1059 -Signed-off-by: Maximilian Luz -Patchset: surface-typecover ---- - drivers/usb/core/quirks.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 13171454f959..a83beefd25f3 100644 ---- a/drivers/usb/core/quirks.c -+++ b/drivers/usb/core/quirks.c -@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { - /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ - { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, - -+ /* Microsoft Surface Go 3 Type-Cover */ -+ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, -+ - /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ - { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, - --- -2.47.1 - -From 3aa9fc5fd7faed0bd5948e80e6ef6173c32a83ca Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 5 Nov 2020 13:09:45 +0100 -Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when - suspending - -The Type Cover for Microsoft Surface devices supports a special usb -control request to disable or enable the built-in keyboard backlight. -On Windows, this request happens when putting the device into suspend or -resuming it, without it the backlight of the Type Cover will remain -enabled for some time even though the computer is suspended, which looks -weird to the user. - -So add support for this special usb control request to hid-multitouch, -which is the driver that's handling the Type Cover. - -The reason we have to use a pm_notifier for this instead of the usual -suspend/resume methods is that those won't get called in case the usb -device is already autosuspended. - -Also, if the device is autosuspended, we have to briefly autoresume it -in order to send the request. Doing that should be fine, the usb-core -driver does something similar during suspend inside choose_wakeup(). - -To make sure we don't send that request to every device but only to -devices which support it, add a new quirk -MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk -is only enabled for the usb id of the Surface Pro 2017 Type Cover, which -is where I confirmed that it's working. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- - 1 file changed, 98 insertions(+), 2 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e936019d21fe..08fee06fb5fc 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -34,7 +34,10 @@ - #include - #include - #include -+#include - #include -+#include -+#include - #include - #include - #include -@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); - MODULE_LICENSE("GPL"); - - #include "hid-ids.h" -+#include "usbhid/usbhid.h" - - /* quirks to control the device */ - #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) -@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 - - #define MT_BUTTONTYPE_CLICKPAD 0 - -+#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+ - enum latency_mode { - HID_LATENCY_NORMAL = 0, - HID_LATENCY_HIGH = 1, -@@ -168,6 +175,8 @@ struct mt_device { - - struct list_head applications; - struct list_head reports; -+ -+ struct notifier_block pm_notifier; - }; - - static void mt_post_parse_default_settings(struct mt_device *td, -@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_GOOGLE 0x0111 - #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 - #define MT_CLS_SMART_TECH 0x0113 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 - #define MT_CLS_SIS 0x0457 - - #define MT_DEFAULT_MAXCONTACT 10 -@@ -402,6 +412,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE, - }, -+ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, -+ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | -+ MT_QUIRK_ALWAYS_VALID | -+ MT_QUIRK_IGNORE_DUPLICATES | -+ MT_QUIRK_HOVERING | -+ MT_QUIRK_CONTACT_CNT_ACCURATE | -+ MT_QUIRK_STICKY_FINGERS | -+ MT_QUIRK_WIN8_PTP_BUTTONS, -+ .export_all_inputs = true -+ }, - { } - }; - -@@ -1751,6 +1771,69 @@ static void mt_expired_timeout(struct timer_list *t) - clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); - } - -+static void get_type_cover_backlight_field(struct hid_device *hdev, -+ struct hid_field **field) -+{ -+ struct hid_report_enum *rep_enum; -+ struct hid_report *rep; -+ struct hid_field *cur_field; -+ int i, j; -+ -+ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; -+ list_for_each_entry(rep, &rep_enum->report_list, list) { -+ for (i = 0; i < rep->maxfield; i++) { -+ cur_field = rep->field[i]; -+ -+ for (j = 0; j < cur_field->maxusage; j++) { -+ if (cur_field->usage[j].hid -+ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { -+ *field = cur_field; -+ return; -+ } -+ } -+ } -+ } -+} -+ -+static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) -+{ -+ struct usb_device *udev = hid_to_usb_dev(hdev); -+ struct hid_field *field = NULL; -+ -+ /* Wake up the device in case it's already suspended */ -+ pm_runtime_get_sync(&udev->dev); -+ -+ get_type_cover_backlight_field(hdev, &field); -+ if (!field) { -+ hid_err(hdev, "couldn't find backlight field\n"); -+ goto out; -+ } -+ -+ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; -+ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); -+ -+out: -+ pm_runtime_put_sync(&udev->dev); -+} -+ -+static int mt_pm_notifier(struct notifier_block *notifier, -+ unsigned long pm_event, -+ void *unused) -+{ -+ struct mt_device *td = -+ container_of(notifier, struct mt_device, pm_notifier); -+ struct hid_device *hdev = td->hdev; -+ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { -+ if (pm_event == PM_SUSPEND_PREPARE) -+ update_keyboard_backlight(hdev, 0); -+ else if (pm_event == PM_POST_SUSPEND) -+ update_keyboard_backlight(hdev, 1); -+ } -+ -+ return NOTIFY_DONE; -+} -+ - static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - { - int ret, i; -@@ -1774,6 +1857,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; - hid_set_drvdata(hdev, td); - -+ td->pm_notifier.notifier_call = mt_pm_notifier; -+ register_pm_notifier(&td->pm_notifier); -+ - INIT_LIST_HEAD(&td->applications); - INIT_LIST_HEAD(&td->reports); - -@@ -1812,8 +1898,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - timer_setup(&td->release_timer, mt_expired_timeout, 0); - - ret = hid_parse(hdev); -- if (ret != 0) -+ if (ret != 0) { -+ unregister_pm_notifier(&td->pm_notifier); - return ret; -+ } - - if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) - mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1822,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - hdev->quirks |= HID_QUIRK_NOGET; - - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); -- if (ret) -+ if (ret) { -+ unregister_pm_notifier(&td->pm_notifier); - return ret; -+ } - - ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); - if (ret) -@@ -1873,6 +1963,7 @@ static void mt_remove(struct hid_device *hdev) - { - struct mt_device *td = hid_get_drvdata(hdev); - -+ unregister_pm_notifier(&td->pm_notifier); - del_timer_sync(&td->release_timer); - - sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2299,6 +2390,11 @@ static const struct hid_device_id mt_devices[] = { - MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, - USB_DEVICE_ID_XIROKU_CSR2) }, - -+ /* Microsoft Surface type cover */ -+ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, -+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, -+ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, -+ - /* Google MT devices */ - { .driver_data = MT_CLS_GOOGLE, - HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, --- -2.47.1 - -From c88ebc0ed1f21ec7ad52aa4fb2c48226603d7596 Mon Sep 17 00:00:00 2001 -From: PJungkamp -Date: Fri, 25 Feb 2022 12:04:25 +0100 -Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet - switch - -The Surface Pro Type Cover has several non standard HID usages in it's -hid report descriptor. -I noticed that, upon folding the typecover back, a vendor specific range -of 4 32 bit integer hid usages is transmitted. -Only the first byte of the message seems to convey reliable information -about the keyboard state. - -0x22 => Normal (keys enabled) -0x33 => Folded back (keys disabled) -0x53 => Rotated left/right side up (keys disabled) -0x13 => Cover closed (keys disabled) -0x43 => Folded back and Tablet upside down (keys disabled) -This list may not be exhaustive. - -The tablet mode switch will be disabled for a value of 0x22 and enabled -on any other value. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ - 1 file changed, 122 insertions(+), 26 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 08fee06fb5fc..f6664049f46d 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); - #define MT_BUTTONTYPE_CLICKPAD 0 - - #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 -+#define MS_TYPE_COVER_APPLICATION 0xff050050 - - enum latency_mode { - HID_LATENCY_NORMAL = 0, -@@ -414,6 +417,7 @@ static const struct mt_class mt_classes[] = { - }, - { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, - .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | -+ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_IGNORE_DUPLICATES | - MT_QUIRK_HOVERING | -@@ -1395,6 +1399,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - field->application != HID_CP_CONSUMER_CONTROL && - field->application != HID_GD_WIRELESS_RADIO_CTLS && - field->application != HID_GD_SYSTEM_MULTIAXIS && -+ !(field->application == MS_TYPE_COVER_APPLICATION && -+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && - !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && - application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) - return -1; -@@ -1422,6 +1429,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - return 1; - } - -+ /* -+ * The Microsoft Surface Pro Typecover has a non-standard HID -+ * tablet mode switch on a vendor specific usage page with vendor -+ * specific usage. -+ */ -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ usage->type = EV_SW; -+ usage->code = SW_TABLET_MODE; -+ *max = SW_MAX; -+ *bit = hi->input->swbit; -+ return 1; -+ } -+ - if (rdata->is_mt_collection) - return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, - application); -@@ -1443,6 +1465,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, - { - struct mt_device *td = hid_get_drvdata(hdev); - struct mt_report_data *rdata; -+ struct input_dev *input; - - rdata = mt_find_report_data(td, field->report); - if (rdata && rdata->is_mt_collection) { -@@ -1450,6 +1473,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, - return -1; - } - -+ /* -+ * We own an input device which acts as a tablet mode switch for -+ * the Surface Pro Typecover. -+ */ -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ input = hi->input; -+ input_set_capability(input, EV_SW, SW_TABLET_MODE); -+ input_report_switch(input, SW_TABLET_MODE, 0); -+ return -1; -+ } -+ - /* let hid-core decide for the others */ - return 0; - } -@@ -1459,11 +1495,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, - { - struct mt_device *td = hid_get_drvdata(hid); - struct mt_report_data *rdata; -+ struct input_dev *input; - - rdata = mt_find_report_data(td, field->report); - if (rdata && rdata->is_mt_collection) - return mt_touch_event(hid, field, usage, value); - -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ input = field->hidinput->input; -+ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); -+ input_sync(input); -+ return 1; -+ } -+ - return 0; - } - -@@ -1641,6 +1687,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) - app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; - } - -+static int get_type_cover_field(struct hid_report_enum *rep_enum, -+ struct hid_field **field, int usage) -+{ -+ struct hid_report *rep; -+ struct hid_field *cur_field; -+ int i, j; -+ -+ list_for_each_entry(rep, &rep_enum->report_list, list) { -+ for (i = 0; i < rep->maxfield; i++) { -+ cur_field = rep->field[i]; -+ if (cur_field->application != MS_TYPE_COVER_APPLICATION) -+ continue; -+ for (j = 0; j < cur_field->maxusage; j++) { -+ if (cur_field->usage[j].hid == usage) { -+ *field = cur_field; -+ return true; -+ } -+ } -+ } -+ } -+ return false; -+} -+ -+static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) -+{ -+ struct hid_field *field; -+ -+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], -+ &field, -+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { -+ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); -+ } else { -+ hid_err(hdev, "couldn't find tablet mode field\n"); -+ } -+} -+ - static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) - { - struct mt_device *td = hid_get_drvdata(hdev); -@@ -1689,6 +1771,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); - break; -+ case MS_TYPE_COVER_APPLICATION: -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { -+ suffix = "Tablet Mode Switch"; -+ request_type_cover_tablet_mode_switch(hdev); -+ break; -+ } -+ fallthrough; - default: - suffix = "UNKNOWN"; - break; -@@ -1771,30 +1860,6 @@ static void mt_expired_timeout(struct timer_list *t) - clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); - } - --static void get_type_cover_backlight_field(struct hid_device *hdev, -- struct hid_field **field) --{ -- struct hid_report_enum *rep_enum; -- struct hid_report *rep; -- struct hid_field *cur_field; -- int i, j; -- -- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; -- list_for_each_entry(rep, &rep_enum->report_list, list) { -- for (i = 0; i < rep->maxfield; i++) { -- cur_field = rep->field[i]; -- -- for (j = 0; j < cur_field->maxusage; j++) { -- if (cur_field->usage[j].hid -- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { -- *field = cur_field; -- return; -- } -- } -- } -- } --} -- - static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) - { - struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1803,8 +1868,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) - /* Wake up the device in case it's already suspended */ - pm_runtime_get_sync(&udev->dev); - -- get_type_cover_backlight_field(hdev, &field); -- if (!field) { -+ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], -+ &field, -+ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { - hid_err(hdev, "couldn't find backlight field\n"); - goto out; - } -@@ -1941,13 +2007,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) - - static int mt_reset_resume(struct hid_device *hdev) - { -+ struct mt_device *td = hid_get_drvdata(hdev); -+ - mt_release_contacts(hdev); - mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); -+ -+ /* Request an update on the typecover folding state on resume -+ * after reset. -+ */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) -+ request_type_cover_tablet_mode_switch(hdev); -+ - return 0; - } - - static int mt_resume(struct hid_device *hdev) - { -+ struct mt_device *td = hid_get_drvdata(hdev); -+ - /* Some Elan legacy devices require SET_IDLE to be set on resume. - * It should be safe to send it to other devices too. - * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1956,12 +2033,31 @@ static int mt_resume(struct hid_device *hdev) - - mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); - -+ /* Request an update on the typecover folding state on resume. */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) -+ request_type_cover_tablet_mode_switch(hdev); -+ - return 0; - } - - static void mt_remove(struct hid_device *hdev) - { - struct mt_device *td = hid_get_drvdata(hdev); -+ struct hid_field *field; -+ struct input_dev *input; -+ -+ /* Reset tablet mode switch on disconnect. */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { -+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], -+ &field, -+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { -+ input = field->hidinput->input; -+ input_report_switch(input, SW_TABLET_MODE, 0); -+ input_sync(input); -+ } else { -+ hid_err(hdev, "couldn't find tablet mode field\n"); -+ } -+ } - - unregister_pm_notifier(&td->pm_notifier); - del_timer_sync(&td->release_timer); --- -2.47.1 - diff --git a/patches/6.14-rc2/0010-surface-shutdown.patch b/patches/6.14-rc2/0010-surface-shutdown.patch deleted file mode 100644 index 9194e85fe8..0000000000 --- a/patches/6.14-rc2/0010-surface-shutdown.patch +++ /dev/null @@ -1,97 +0,0 @@ -From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod - -Work around buggy EFI firmware: On some Microsoft Surface devices -(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with -EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the -system down, it returns and the system stays on. - -It turns out that this only happens after PCI shutdown callbacks ran for -specific devices. Excluding those devices from the shutdown process -makes the ResetSystem call work as expected. - -TODO: Maybe we can find a better way or the root cause of this? - -Not-Signed-off-by: Maximilian Luz -Patchset: surface-shutdown ---- - drivers/pci/pci-driver.c | 3 +++ - drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ - include/linux/pci.h | 1 + - 3 files changed, 40 insertions(+) - -diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 35270172c833..529779994ef6 100644 ---- a/drivers/pci/pci-driver.c -+++ b/drivers/pci/pci-driver.c -@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) - struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = pci_dev->driver; - -+ if (pci_dev->no_shutdown) -+ return; -+ - pm_runtime_resume(dev); - - if (drv && drv->shutdown) -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 8103bc24a54e..e8fa8d810925 100644 ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -6301,3 +6301,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); - #endif -+ -+static const struct dmi_system_id no_shutdown_dmi_table[] = { -+ /* -+ * Systems on which some devices should not be touched during shutdown. -+ */ -+ { -+ .ident = "Microsoft Surface Pro 9", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), -+ }, -+ }, -+ { -+ .ident = "Microsoft Surface Laptop 5", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), -+ }, -+ }, -+ {} -+}; -+ -+static void quirk_no_shutdown(struct pci_dev *dev) -+{ -+ if (!dmi_check_system(no_shutdown_dmi_table)) -+ return; -+ -+ dev->no_shutdown = 1; -+ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", -+ dev->vendor, dev->device); -+} -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU -diff --git a/include/linux/pci.h b/include/linux/pci.h -index 4e77c4230c0a..a4b0e6ef6cfe 100644 ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -467,6 +467,7 @@ struct pci_dev { - unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ - unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ - unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ -+ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; /* pci_enable_device has been called */ - --- -2.47.1 - diff --git a/patches/6.14-rc2/0011-surface-gpe.patch b/patches/6.14-rc2/0011-surface-gpe.patch deleted file mode 100644 index cb83acb03c..0000000000 --- a/patches/6.14-rc2/0011-surface-gpe.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 8120dc21068acfe547e9c6d1cced417e5931c7ad Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 12 Mar 2023 01:41:57 +0100 -Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 - -Add the lid GPE used by the Surface Pro 9. - -Signed-off-by: Maximilian Luz -Patchset: surface-gpe ---- - drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index 62fd4004db31..103fc4468262 100644 ---- a/drivers/platform/surface/surface_gpe.c -+++ b/drivers/platform/surface/surface_gpe.c -@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { - {}, - }; - -+static const struct property_entry lid_device_props_l52[] = { -+ PROPERTY_ENTRY_U32("gpe", 0x52), -+ {}, -+}; -+ - static const struct property_entry lid_device_props_l57[] = { - PROPERTY_ENTRY_U32("gpe", 0x57), - {}, -@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { - }, - .driver_data = (void *)lid_device_props_l4B, - }, -+ { -+ /* -+ * We match for SKU here due to product name clash with the ARM -+ * version. -+ */ -+ .ident = "Surface Pro 9", -+ .matches = { -+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), -+ }, -+ .driver_data = (void *)lid_device_props_l52, -+ }, - { - .ident = "Surface Book 1", - .matches = { --- -2.47.1 - diff --git a/patches/6.14-rc2/0012-cameras.patch b/patches/6.14-rc2/0012-cameras.patch deleted file mode 100644 index 64014fd030..0000000000 --- a/patches/6.14-rc2/0012-cameras.patch +++ /dev/null @@ -1,734 +0,0 @@ -From 2cb3cbe91cb78a8747e6eee341c1d4e20c459d16 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sun, 10 Oct 2021 20:56:57 +0200 -Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an - INT3472 device - -The clk and regulator frameworks expect clk/regulator consumer-devices -to have info about the consumed clks/regulators described in the device's -fw_node. - -To work around cases where this info is not present in the firmware tables, -which is often the case on x86/ACPI devices, both frameworks allow the -provider-driver to attach info about consumers to the clks/regulators -when registering these. - -This causes problems with the probe ordering wrt drivers for consumers -of these clks/regulators. Since the lookups are only registered when the -provider-driver binds, trying to get these clks/regulators before then -results in a -ENOENT error for clks and a dummy regulator for regulators. - -One case where we hit this issue is camera sensors such as e.g. the OV8865 -sensor found on the Microsoft Surface Go. The sensor uses clks, regulators -and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 -ACPI device. There is special platform code handling this and setting -platform_data with the necessary consumer info on the MFD cells -instantiated for the PMIC under: drivers/platform/x86/intel/int3472. - -For this to work properly the ov8865 driver must not bind to the I2C-client -for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and -clk MFD cells have all been fully setup. - -The OV8865 on the Microsoft Surface Go is just one example, all X86 -devices using the Intel IPU3 camera block found on recent Intel SoCs -have similar issues where there is an INT3472 HID ACPI-device, which -describes the clks and regulators, and the driver for this INT3472 device -must be fully initialized before the sensor driver (any sensor driver) -binds for things to work properly. - -On these devices the ACPI nodes describing the sensors all have a _DEP -dependency on the matching INT3472 ACPI device (there is one per sensor). - -This allows solving the probe-ordering problem by delaying the enumeration -(instantiation of the I2C-client in the ov8865 example) of ACPI-devices -which have a _DEP dependency on an INT3472 device. - -The new acpi_dev_ready_for_enumeration() helper used for this is also -exported because for devices, which have the enumeration_by_parent flag -set, the parent-driver will do its own scan of child ACPI devices and -it will try to enumerate those during its probe(). Code doing this such -as e.g. the i2c-core-acpi.c code must call this new helper to ensure -that it too delays the enumeration until all the _DEP dependencies are -met on devices which have the new honor_deps flag set. - -Signed-off-by: Hans de Goede -Patchset: cameras ---- - drivers/acpi/scan.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 7ecc401fb97f..e35185de1902 100644 ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, - - static void acpi_default_enumeration(struct acpi_device *device) - { -+ if (!acpi_dev_ready_for_enumeration(device)) -+ return; -+ - /* - * Do not enumerate devices with enumeration_by_parent flag set as - * they will be enumerated by their respective parents. --- -2.47.1 - -From 29efdd823d22e0a6f7dead43d9c309602a1d2cbd Mon Sep 17 00:00:00 2001 -From: zouxiaoh -Date: Fri, 25 Jun 2021 08:52:59 +0800 -Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs - -Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, -The IPU driver allocates its own page table that is not mapped -via the DMA, and thus the Intel IOMMU driver blocks access giving -this error: DMAR: DRHD: handling fault status reg 3 DMAR: -[DMA Read] Request device [00:05.0] PASID ffffffff -fault addr 76406000 [fault reason 06] PTE Read access is not set -As IPU is not an external facing device which is not risky, so use -IOMMU passthrough mode for Intel IPUs. - -Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b -Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 -Tracked-On: #JIITL8-411 -Signed-off-by: Bingbu Cao -Signed-off-by: zouxiaoh -Signed-off-by: Xu Chongyang -Patchset: cameras ---- - drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index c010aebe6cc1..42b342184d56 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -45,6 +45,13 @@ - ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ - ) - -+#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ -+ ((pdev)->device == 0x9a19 || \ -+ (pdev)->device == 0x9a39 || \ -+ (pdev)->device == 0x4e19 || \ -+ (pdev)->device == 0x465d || \ -+ (pdev)->device == 0x1919)) -+ - #define IOAPIC_RANGE_START (0xfee00000) - #define IOAPIC_RANGE_END (0xfeefffff) - #define IOVA_START_ADDR (0x1000) -@@ -214,12 +221,14 @@ int intel_iommu_enabled = 0; - EXPORT_SYMBOL_GPL(intel_iommu_enabled); - - static int dmar_map_ipts = 1; -+static int dmar_map_ipu = 1; - static int intel_iommu_superpage = 1; - static int iommu_identity_mapping; - static int iommu_skip_te_disable; - static int disable_igfx_iommu; - - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPU 8 - #define IDENTMAP_IPTS 16 - - const struct iommu_ops intel_iommu_ops; -@@ -2054,6 +2063,9 @@ static int device_def_domain_type(struct device *dev) - if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) - return IOMMU_DOMAIN_IDENTITY; - -+ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; -+ - if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) - return IOMMU_DOMAIN_IDENTITY; - } -@@ -2354,6 +2366,9 @@ static int __init init_dmars(void) - iommu_set_root_entry(iommu); - } - -+ if (!dmar_map_ipu) -+ iommu_identity_mapping |= IDENTMAP_IPU; -+ - if (!dmar_map_ipts) - iommu_identity_mapping |= IDENTMAP_IPTS; - -@@ -4664,6 +4679,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - disable_igfx_iommu = 1; - } - -+static void quirk_iommu_ipu(struct pci_dev *dev) -+{ -+ if (!IS_INTEL_IPU(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; -+ -+ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); -+ dmar_map_ipu = 0; -+} -+ - static void quirk_iommu_ipts(struct pci_dev *dev) - { - if (!IS_IPTS(dev)) -@@ -4711,6 +4738,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); - -+/* disable IPU dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); -+ - /* disable IPTS dmar support */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); --- -2.47.1 - -From 503ddf1a3c915d4b1108b44a280fd588fd11252c Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Sun, 10 Oct 2021 20:57:02 +0200 -Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain - -The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic -can be forwarded to a device connected to the PMIC as though it were -connected directly to the system bus. Enable this mode when the chip -is initialised. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 1e107fd49f82..e3e1696e7f0e 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) - return ret; - } - -+ /* Enable I2C daisy chain */ -+ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); -+ if (ret) { -+ dev_err(dev, "Failed to enable i2c daisy chain\n"); -+ return ret; -+ } -+ - dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); - - return 0; --- -2.47.1 - -From 46806f2df854794beb466026561dc6446ec77632 Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Thu, 2 Mar 2023 12:59:39 +0000 -Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E - -ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The -driver for this sensor expects a single pin named "enable", but on -some Microsoft Surface platforms the sensor is assigned a single -GPIO who's type flag is INT3472_GPIO_TYPE_RESET. - -Remap the GPIO pin's function from "reset" to "enable". This is done -outside of the existing remap table since it is a more widespread -discrepancy than that method is designed for. Additionally swap the -polarity of the pin to match the driver's expectation. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 3de463c3d13b..0a012eeed30a 100644 ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - const char *func, u32 polarity) - { - int ret; -+ const struct acpi_device_id ov7251_ids[] = { -+ { "INT347E" }, -+ { } -+ }; - - if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { - dev_warn(int3472->dev, "Too many GPIOs mapped\n"); - return -EINVAL; - } - -+ /* -+ * In addition to the function remap table we need to bulk remap the -+ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that -+ * expects its only GPIO pin to be called "enable" (and to have the -+ * opposite polarity). -+ */ -+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { -+ func = "enable"; -+ polarity ^= GPIO_ACTIVE_LOW; -+ } -+ - ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, func, polarity); - if (ret) --- -2.47.1 - -From af26f5acd84f8f7db95873690902562a159a94fb Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Tue, 21 Mar 2023 13:45:26 +0000 -Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 - -Update the control ID for the gain control in the ov7251 driver to -V4L2_CID_ANALOGUE_GAIN. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/media/i2c/ov7251.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf..9c1292ca8552 100644 ---- a/drivers/media/i2c/ov7251.c -+++ b/drivers/media/i2c/ov7251.c -@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) - case V4L2_CID_EXPOSURE: - ret = ov7251_set_exposure(ov7251, ctrl->val); - break; -- case V4L2_CID_GAIN: -+ case V4L2_CID_ANALOGUE_GAIN: - ret = ov7251_set_gain(ov7251, ctrl->val); - break; - case V4L2_CID_TEST_PATTERN: -@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) - ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, - V4L2_CID_EXPOSURE, 1, 32, 1, 32); - ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, -- V4L2_CID_GAIN, 16, 1023, 1, 16); -+ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); - v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, - V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(ov7251_test_pattern_menu) - 1, --- -2.47.1 - -From d0bcf0400f018b7d505f47bcf21ef7843f1372ca Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Wed, 22 Mar 2023 11:01:42 +0000 -Subject: [PATCH] media: v4l2-core: Acquire privacy led in - v4l2_async_register_subdev() - -The current call to v4l2_subdev_get_privacy_led() is contained in -v4l2_async_register_subdev_sensor(), but that function isn't used by -all the sensor drivers. Move the acquisition of the privacy led to -v4l2_async_register_subdev() instead. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/media/v4l2-core/v4l2-async.c | 4 ++++ - drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index ee884a8221fb..4f6bafd900ee 100644 ---- a/drivers/media/v4l2-core/v4l2-async.c -+++ b/drivers/media/v4l2-core/v4l2-async.c -@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) - - INIT_LIST_HEAD(&sd->asc_list); - -+ ret = v4l2_subdev_get_privacy_led(sd); -+ if (ret < 0) -+ return ret; -+ - /* - * No reference taken. The reference is held by the device (struct - * v4l2_subdev.dev), and async sub-device does not exist independently -diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index f19c8adf2c61..923ed1b5ab8b 100644 ---- a/drivers/media/v4l2-core/v4l2-fwnode.c -+++ b/drivers/media/v4l2-core/v4l2-fwnode.c -@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) - - v4l2_async_subdev_nf_init(notifier, sd); - -- ret = v4l2_subdev_get_privacy_led(sd); -- if (ret < 0) -- goto out_cleanup; -- - ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); - if (ret < 0) - goto out_cleanup; --- -2.47.1 - -From 222586440493b857e7c5aa363f8741b7fff753be Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:16 +0800 -Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED - -Add MFD cell for tps68470-led. - -Reviewed-by: Daniel Scally -Signed-off-by: Kate Hsuan -Reviewed-by: Hans de Goede -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index e3e1696e7f0e..423dc555093f 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -17,7 +17,7 @@ - #define DESIGNED_FOR_CHROMEOS 1 - #define DESIGNED_FOR_WINDOWS 2 - --#define TPS68470_WIN_MFD_CELL_COUNT 3 -+#define TPS68470_WIN_MFD_CELL_COUNT 4 - - static const struct mfd_cell tps68470_cros[] = { - { .name = "tps68470-gpio" }, -@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) - cells[1].name = "tps68470-regulator"; - cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; - cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); -- cells[2].name = "tps68470-gpio"; -+ cells[2].name = "tps68470-led"; -+ cells[3].name = "tps68470-gpio"; - - for (i = 0; i < board_data->n_gpiod_lookups; i++) - gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); --- -2.47.1 - -From b0e450741669b478b74d8610fd9dbae817962077 Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:17 +0800 -Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB - -Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB -(TPS68470_ILEDCTL_ENB), and current control mask for LEDB -(TPS68470_ILEDCTL_CTRLB) - -Reviewed-by: Daniel Scally -Reviewed-by: Hans de Goede -Signed-off-by: Kate Hsuan -Patchset: cameras ---- - include/linux/mfd/tps68470.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 ---- a/include/linux/mfd/tps68470.h -+++ b/include/linux/mfd/tps68470.h -@@ -34,6 +34,7 @@ - #define TPS68470_REG_SGPO 0x22 - #define TPS68470_REG_GPDI 0x26 - #define TPS68470_REG_GPDO 0x27 -+#define TPS68470_REG_ILEDCTL 0x28 - #define TPS68470_REG_VCMVAL 0x3C - #define TPS68470_REG_VAUX1VAL 0x3D - #define TPS68470_REG_VAUX2VAL 0x3E -@@ -94,4 +95,8 @@ - #define TPS68470_GPIO_MODE_OUT_CMOS 2 - #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 - -+#define TPS68470_ILEDCTL_ENA BIT(2) -+#define TPS68470_ILEDCTL_ENB BIT(6) -+#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) -+ - #endif /* __LINUX_MFD_TPS68470_H */ --- -2.47.1 - -From 7f546475ba781cf67aedd9817046b506873edab1 Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:18 +0800 -Subject: [PATCH] leds: tps68470: Add LED control for tps68470 - -There are two LED controllers, LEDA indicator LED and LEDB flash LED for -tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, -tps68470 provides four levels of power status for LEDB. If the -properties called "ti,ledb-current" can be found, the current will be -set according to the property values. These two LEDs can be controlled -through the LED class of sysfs (tps68470-leda and tps68470-ledb). - -Signed-off-by: Kate Hsuan -Reviewed-by: Hans de Goede -Patchset: cameras ---- - drivers/leds/Kconfig | 12 +++ - drivers/leds/Makefile | 1 + - drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ - 3 files changed, 198 insertions(+) - create mode 100644 drivers/leds/leds-tps68470.c - -diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index b784bb74a837..f8d8fcfacac2 100644 ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -941,6 +941,18 @@ config LEDS_TPS6105X - It is a single boost converter primarily for white LEDs and - audio amplifiers. - -+config LEDS_TPS68470 -+ tristate "LED support for TI TPS68470" -+ depends on LEDS_CLASS -+ depends on INTEL_SKL_INT3472 -+ help -+ This driver supports TPS68470 PMIC with LED chip. -+ It provides two LED controllers, with the ability to drive 2 -+ indicator LEDs and 2 flash LEDs. -+ -+ To compile this driver as a module, choose M and it will be -+ called leds-tps68470 -+ - config LEDS_IP30 - tristate "LED support for SGI Octane machines" - depends on LEDS_CLASS -diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 18afbb5a23ee..a1d16c0af82d 100644 ---- a/drivers/leds/Makefile -+++ b/drivers/leds/Makefile -@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o - obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o - obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o - obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o -+obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o - obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o - obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o - obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o -diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c -new file mode 100644 -index 000000000000..35aeb5db89c8 ---- /dev/null -+++ b/drivers/leds/leds-tps68470.c -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * LED driver for TPS68470 PMIC -+ * -+ * Copyright (C) 2023 Red Hat -+ * -+ * Authors: -+ * Kate Hsuan -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define lcdev_to_led(led_cdev) \ -+ container_of(led_cdev, struct tps68470_led, lcdev) -+ -+#define led_to_tps68470(led, index) \ -+ container_of(led, struct tps68470_device, leds[index]) -+ -+enum tps68470_led_ids { -+ TPS68470_ILED_A, -+ TPS68470_ILED_B, -+ TPS68470_NUM_LEDS -+}; -+ -+static const char *tps68470_led_names[] = { -+ [TPS68470_ILED_A] = "tps68470-iled_a", -+ [TPS68470_ILED_B] = "tps68470-iled_b", -+}; -+ -+struct tps68470_led { -+ unsigned int led_id; -+ struct led_classdev lcdev; -+}; -+ -+struct tps68470_device { -+ struct device *dev; -+ struct regmap *regmap; -+ struct tps68470_led leds[TPS68470_NUM_LEDS]; -+}; -+ -+enum ctrlb_current { -+ CTRLB_2MA = 0, -+ CTRLB_4MA = 1, -+ CTRLB_8MA = 2, -+ CTRLB_16MA = 3, -+}; -+ -+static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) -+{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, -+ brightness ? TPS68470_ILEDCTL_ENA : 0); -+ case TPS68470_ILED_B: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, -+ brightness ? TPS68470_ILEDCTL_ENB : 0); -+ } -+ return -EINVAL; -+} -+ -+static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) -+{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ int ret = 0; -+ int value = 0; -+ -+ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); -+ if (ret) -+ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); -+ -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ value = value & TPS68470_ILEDCTL_ENA; -+ break; -+ case TPS68470_ILED_B: -+ value = value & TPS68470_ILEDCTL_ENB; -+ break; -+ } -+ -+ return value ? LED_ON : LED_OFF; -+} -+ -+ -+static int tps68470_ledb_current_init(struct platform_device *pdev, -+ struct tps68470_device *tps68470) -+{ -+ int ret = 0; -+ unsigned int curr; -+ -+ /* configure LEDB current if the properties can be got */ -+ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { -+ if (curr > CTRLB_16MA) { -+ dev_err(&pdev->dev, -+ "Invalid LEDB current value: %d\n", -+ curr); -+ return -EINVAL; -+ } -+ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, -+ TPS68470_ILEDCTL_CTRLB, curr); -+ } -+ return ret; -+} -+ -+static int tps68470_leds_probe(struct platform_device *pdev) -+{ -+ int i = 0; -+ int ret = 0; -+ struct tps68470_device *tps68470; -+ struct tps68470_led *led; -+ struct led_classdev *lcdev; -+ -+ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), -+ GFP_KERNEL); -+ if (!tps68470) -+ return -ENOMEM; -+ -+ tps68470->dev = &pdev->dev; -+ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); -+ -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ led = &tps68470->leds[i]; -+ lcdev = &led->lcdev; -+ -+ led->led_id = i; -+ -+ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", -+ tps68470_led_names[i], LED_FUNCTION_INDICATOR); -+ if (!lcdev->name) -+ return -ENOMEM; -+ -+ lcdev->max_brightness = 1; -+ lcdev->brightness = 0; -+ lcdev->brightness_set_blocking = tps68470_brightness_set; -+ lcdev->brightness_get = tps68470_brightness_get; -+ lcdev->dev = &pdev->dev; -+ -+ ret = devm_led_classdev_register(tps68470->dev, lcdev); -+ if (ret) { -+ dev_err_probe(tps68470->dev, ret, -+ "error registering led\n"); -+ goto err_exit; -+ } -+ -+ if (i == TPS68470_ILED_B) { -+ ret = tps68470_ledb_current_init(pdev, tps68470); -+ if (ret) -+ goto err_exit; -+ } -+ } -+ -+err_exit: -+ if (ret) { -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ if (tps68470->leds[i].lcdev.name) -+ devm_led_classdev_unregister(&pdev->dev, -+ &tps68470->leds[i].lcdev); -+ } -+ } -+ -+ return ret; -+} -+static struct platform_driver tps68470_led_driver = { -+ .driver = { -+ .name = "tps68470-led", -+ }, -+ .probe = tps68470_leds_probe, -+}; -+ -+module_platform_driver(tps68470_led_driver); -+ -+MODULE_ALIAS("platform:tps68470-led"); -+MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); -+MODULE_LICENSE("GPL v2"); --- -2.47.1 - -From adf794d65cca167d5bc66ef0c8a160e3fbeb3481 Mon Sep 17 00:00:00 2001 -From: mojyack -Date: Tue, 26 Mar 2024 05:55:44 +0900 -Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 - -On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". -The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. -So just add some delay. -There is no exact reason for this 10000us, but 100us failed. - -Patchset: cameras ---- - drivers/media/i2c/dw9719.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..0094cfda57ea 100644 ---- a/drivers/media/i2c/dw9719.c -+++ b/drivers/media/i2c/dw9719.c -@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) - if (ret) - return ret; - -+ /* Wait for device to be acknowledged */ -+ fsleep(10000); -+ - /* Jiggle SCL pin to wake up device */ - cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); - --- -2.47.1 - diff --git a/patches/6.14-rc2/0013-amd-gpio.patch b/patches/6.14-rc2/0013-amd-gpio.patch deleted file mode 100644 index 93c8956a23..0000000000 --- a/patches/6.14-rc2/0013-amd-gpio.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 28b8120e4f9b02ec49ccedd036557552a1aee5dc Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Sat, 29 May 2021 17:47:38 +1000 -Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 - override - -This patch is the work of Thomas Gleixner and is -copied from: -https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ - -This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin -setup that is missing in the laptops ACPI table. - -This patch was used for validation of the issue, and is not a proper -fix, but is probably a better temporary hack than continuing to probe -the Legacy PIC and run with the PIC in an unknown state. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 4efecac49863..88377bb0d137 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) - } - } - -+static const struct dmi_system_id surface_quirk[] __initconst = { -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") -+ }, -+ }, -+ {} -+}; -+ - /* - * Parse IOAPIC related entries in MADT - * returns 0 on success, < 0 on error -@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) - acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, - acpi_gbl_FADT.sci_interrupt); - -+ if (dmi_check_system(surface_quirk)) { -+ pr_warn("Surface hack: Override irq 7\n"); -+ mp_override_legacy_irq(7, 3, 3, 7); -+ } -+ - /* Fill in identity legacy mappings where no override */ - mp_config_acpi_legacy_irqs(); - --- -2.47.1 - -From 1b801d759aced457e5508cf931fa849400233b92 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Thu, 3 Jun 2021 14:04:26 +0200 -Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override - quirk - -The 13" version of the Surface Laptop 4 has the same problem as the 15" -version, but uses a different SKU. Add that SKU to the quirk as well. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 88377bb0d137..c58f26918b17 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) - - static const struct dmi_system_id surface_quirk[] __initconst = { - { -- .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") - }, - }, -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") -+ }, -+ }, - {} - }; - --- -2.47.1 - diff --git a/patches/6.14-rc2/0014-rtc.patch b/patches/6.14-rc2/0014-rtc.patch deleted file mode 100644 index 784921d06d..0000000000 --- a/patches/6.14-rc2/0014-rtc.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 0a6b868f61d7564bc898ac30c84fbf3c34fb7368 Mon Sep 17 00:00:00 2001 -From: "Bart Groeneveld | GPX Solutions B.V" -Date: Mon, 5 Dec 2022 16:08:46 +0100 -Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms - -The specification [1] allows so-called HW-reduced platforms, -which do not implement everything, especially the wakeup related stuff. - -In that case, it is still usable as a RTC. This is helpful for [2] -and [3], which is about a device with no other working RTC, -but it does have an HW-reduced TAD, which can be used as a RTC instead. - -[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device -[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 -[3]: https://github.com/linux-surface/linux-surface/issues/415 - -Signed-off-by: Bart Groeneveld | GPX Solutions B.V. -Patchset: rtc ---- - drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ - 1 file changed, 24 insertions(+), 12 deletions(-) - -diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index b831cb8e53dc..78bd0f926505 100644 ---- a/drivers/acpi/acpi_tad.c -+++ b/drivers/acpi/acpi_tad.c -@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RO(caps); - -+static struct attribute *acpi_tad_attrs[] = { -+ &dev_attr_caps.attr, -+ NULL, -+}; -+static const struct attribute_group acpi_tad_attr_group = { -+ .attrs = acpi_tad_attrs, -+}; -+ - static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) - { -@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RW(ac_status); - --static struct attribute *acpi_tad_attrs[] = { -- &dev_attr_caps.attr, -+static struct attribute *acpi_tad_ac_attrs[] = { - &dev_attr_ac_alarm.attr, - &dev_attr_ac_policy.attr, - &dev_attr_ac_status.attr, - NULL, - }; --static const struct attribute_group acpi_tad_attr_group = { -- .attrs = acpi_tad_attrs, -+static const struct attribute_group acpi_tad_ac_attr_group = { -+ .attrs = acpi_tad_ac_attrs, - }; - - static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, -@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) - - pm_runtime_get_sync(dev); - -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) -+ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ - if (dd->capabilities & ACPI_TAD_DC_WAKE) - sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); - - sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); - -- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) { -+ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -+ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ } - if (dd->capabilities & ACPI_TAD_DC_WAKE) { - acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); - acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); -@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) - goto remove_handler; - } - -- if (!acpi_has_method(handle, "_PRW")) { -- dev_info(dev, "Missing _PRW\n"); -- ret = -ENODEV; -- goto remove_handler; -- } -- - dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); - if (!dd) { - ret = -ENOMEM; -@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) - if (ret) - goto fail; - -+ if (caps & ACPI_TAD_AC_WAKE) { -+ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ if (ret) -+ goto fail; -+ } -+ - if (caps & ACPI_TAD_DC_WAKE) { - ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); - if (ret) --- -2.47.1 - diff --git a/patches/6.14-rc4/0001-secureboot.patch b/patches/6.14-rc4/0001-secureboot.patch deleted file mode 100644 index addb86e813..0000000000 --- a/patches/6.14-rc4/0001-secureboot.patch +++ /dev/null @@ -1,112 +0,0 @@ -From bbcfb18eb05bd92e4501ca35bdfd558c849ddeda Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 9 Jun 2024 19:48:58 +0200 -Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag - unconditionally" - -This reverts commit 891f8890a4a3663da7056542757022870b499bc1. - -Revert because of compatibility issues of MS Surface devices and GRUB -with NX. In short, these devices get stuck on boot with NX advertised. -So to not advertise it, add the respective option back in. - -Signed-off-by: Maximilian Luz -Patchset: secureboot ---- - arch/x86/boot/header.S | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index b5c79f43359b..a1bbedd989e4 100644 ---- a/arch/x86/boot/header.S -+++ b/arch/x86/boot/header.S -@@ -111,7 +111,11 @@ extra_header_fields: - .long salign # SizeOfHeaders - .long 0 # CheckSum - .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) -+#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES - .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics -+#else -+ .word 0 # DllCharacteristics -+#endif - #ifdef CONFIG_X86_32 - .long 0 # SizeOfStackReserve - .long 0 # SizeOfStackCommit --- -2.47.1 - -From 9a796344897d077f1fc977ab026315c2cfcd3960 Mon Sep 17 00:00:00 2001 -From: "J. Eduardo" -Date: Sun, 25 Aug 2024 14:17:45 +0200 -Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter - -This allows the user to tell the kernel that they know better (namely, -they secured their swap properly), and that it can enable hibernation. - -Signed-off-by: Kelvie Wong -Link: https://github.com/linux-surface/kernel/pull/158 -Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee -Patchset: secureboot ---- - Documentation/admin-guide/kernel-parameters.txt | 5 +++++ - kernel/power/hibernate.c | 10 +++++++++- - 2 files changed, 14 insertions(+), 1 deletion(-) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index d401577b5a6a..5a812e0b740a 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3066,6 +3066,11 @@ - to extract confidential information from the kernel - are also disabled. - -+ lockdown_hibernate [HIBERNATION] -+ Enable hibernation even if lockdown is enabled. Enable this only if -+ your swap is encrypted and secured properly, as an attacker can -+ modify the kernel offline during hibernation. -+ - locktorture.acq_writer_lim= [KNL] - Set the time limit in jiffies for a lock - acquisition. Acquisitions exceeding this limit -diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index e35829d36039..6d54eb03b63d 100644 ---- a/kernel/power/hibernate.c -+++ b/kernel/power/hibernate.c -@@ -37,6 +37,7 @@ - #include "power.h" - - -+static int lockdown_hibernate; - static int nocompress; - static int noresume; - static int nohibernate; -@@ -92,7 +93,7 @@ void hibernate_release(void) - bool hibernation_available(void) - { - return nohibernate == 0 && -- !security_locked_down(LOCKDOWN_HIBERNATION) && -+ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && - !secretmem_active() && !cxl_mem_active(); - } - -@@ -1426,6 +1427,12 @@ static int __init nohibernate_setup(char *str) - return 1; - } - -+static int __init lockdown_hibernate_setup(char *str) -+{ -+ lockdown_hibernate = 1; -+ return 1; -+} -+ - static const char * const comp_alg_enabled[] = { - #if IS_ENABLED(CONFIG_CRYPTO_LZO) - COMPRESSION_ALGO_LZO, -@@ -1484,3 +1491,4 @@ __setup("hibernate=", hibernate_setup); - __setup("resumewait", resumewait_setup); - __setup("resumedelay=", resumedelay_setup); - __setup("nohibernate", nohibernate_setup); -+__setup("lockdown_hibernate", lockdown_hibernate_setup); --- -2.47.1 - diff --git a/patches/6.14-rc4/0002-surface3-oemb.patch b/patches/6.14-rc4/0002-surface3-oemb.patch deleted file mode 100644 index ab40dd606c..0000000000 --- a/patches/6.14-rc4/0002-surface3-oemb.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 2ce5cf2a597c9015c64ea9f386a396f97b8589c6 Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 18 Oct 2020 16:42:44 +0900 -Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI - table - -On some Surface 3, the DMI table gets corrupted for unknown reasons -and breaks existing DMI matching used for device-specific quirks. - -This commit adds the (broken) DMI data into dmi_system_id tables used -for quirks so that each driver can enable quirks even on the affected -systems. - -On affected systems, DMI data will look like this: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:OEMB - /sys/devices/virtual/dmi/id/board_vendor:OEMB - /sys/devices/virtual/dmi/id/chassis_vendor:OEMB - /sys/devices/virtual/dmi/id/product_name:OEMB - /sys/devices/virtual/dmi/id/sys_vendor:OEMB - -Expected: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:Surface 3 - /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/product_name:Surface 3 - /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation - -Signed-off-by: Tsuchiya Yuto -Patchset: surface3-oemb ---- - drivers/platform/surface/surface3-wmi.c | 7 +++++++ - sound/soc/codecs/rt5645.c | 9 +++++++++ - sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ - 3 files changed, 24 insertions(+) - -diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index c15ed7a12784..1ec8edb5aafa 100644 ---- a/drivers/platform/surface/surface3-wmi.c -+++ b/drivers/platform/surface/surface3-wmi.c -@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - #endif - { } - }; -diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 51187b1e0ed2..bfb83ce8d8f8 100644 ---- a/sound/soc/codecs/rt5645.c -+++ b/sound/soc/codecs/rt5645.c -@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { - }, - .driver_data = (void *)&intel_braswell_platform_data, - }, -+ { -+ .ident = "Microsoft Surface 3", -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ .driver_data = (void *)&intel_braswell_platform_data, -+ }, - { - /* - * Match for the GPDwin which unfortunately uses somewhat -diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0c28..0b930c91bccb 100644 ---- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .callback = cht_surface_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - { } - }; - --- -2.47.1 - diff --git a/patches/6.14-rc4/0003-mwifiex.patch b/patches/6.14-rc4/0003-mwifiex.patch deleted file mode 100644 index 523a943588..0000000000 --- a/patches/6.14-rc4/0003-mwifiex.patch +++ /dev/null @@ -1,400 +0,0 @@ -From ed54461506b98c1bc8ae8dc5f7385de1f900ed0b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Tue, 3 Nov 2020 13:28:04 +0100 -Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface - devices - -The most recent firmware of the 88W8897 card reports a hardcoded LTR -value to the system during initialization, probably as an (unsuccessful) -attempt of the developers to fix firmware crashes. This LTR value -prevents most of the Microsoft Surface devices from entering deep -powersaving states (either platform C-State 10 or S0ix state), because -the exit latency of that state would be higher than what the card can -tolerate. - -Turns out the card works just the same (including the firmware crashes) -no matter if that hardcoded LTR value is reported or not, so it's kind -of useless and only prevents us from saving power. - -To get rid of those hardcoded LTR reports, it's possible to reset the -PCI bridge device after initializing the cards firmware. I'm not exactly -sure why that works, maybe the power management subsystem of the PCH -resets its stored LTR values when doing a function level reset of the -bridge device. Doing the reset once after starting the wifi firmware -works very well, probably because the firmware only reports that LTR -value a single time during firmware startup. - -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 3 files changed, 31 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 5f997becdbaa..9a9929424513 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) - static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) - { - struct pcie_service_card *card = adapter->card; -+ struct pci_dev *pdev = card->dev; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; - -+ /* Trigger a function level reset of the PCI bridge device, this makes -+ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value -+ * that prevents the system from entering package C10 and S0ix powersaving -+ * states. -+ * We need to do it here because it must happen after firmware -+ * initialization and this function is called after that is done. -+ */ -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ pci_reset_function(parent_pdev); -+ - /* Write the RX ring read pointer in to reg->rx_rdptr */ - mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); - } -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5", -@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 6", -@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 1", -@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 2", -@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 1", -@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 2", -@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - {} - }; -@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "no quirks enabled\n"); - if (card->quirks & QUIRK_FW_RST_D3COLD) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); - } - - static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -4,6 +4,7 @@ - #include "pcie.h" - - #define QUIRK_FW_RST_D3COLD BIT(0) -+#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) - - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.47.1 - -From a93a869673e056cf2a2c46b9438edaca8f5e2645 Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 4 Oct 2020 00:11:49 +0900 -Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ - -Currently, mwifiex fw will crash after suspend on recent kernel series. -On Windows, it seems that the root port of wifi will never enter D3 state -(stay on D0 state). And on Linux, disabling the D3 state for the -bridge fixes fw crashing after suspend. - -This commit disables the D3 state of root port on driver initialization -and fixes fw crashing after suspend. - -Signed-off-by: Tsuchiya Yuto -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 3 files changed, 27 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 9a9929424513..2273e3029776 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) - { - struct pcie_service_card *card; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - int ret; - - pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", -@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - return -1; - } - -+ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing -+ * after suspend -+ */ -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ parent_pdev->bridge_d3 = false; -+ - return 0; - } - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5", -@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 6", -@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 1", -@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 2", -@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 1", -@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 2", -@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - {} - }; -@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); - if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) - dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ dev_info(&pdev->dev, -+ "quirk no_brigde_d3 enabled\n"); - } - - static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -5,6 +5,7 @@ - - #define QUIRK_FW_RST_D3COLD BIT(0) - #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) -+#define QUIRK_NO_BRIDGE_D3 BIT(2) - - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.47.1 - -From bcc616a02ed2a9e059d2e7a1dd5b5289412efcbb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 25 Mar 2021 11:33:02 +0100 -Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell - 88W8897 - -The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) -is used in a lot of Microsoft Surface devices, and all those devices -suffer from very low 2.4GHz wifi connection speeds while bluetooth is -enabled. The reason for that is that the default passive scanning -interval for Bluetooth Low Energy devices is quite high in Linux -(interval of 60 msec and scan window of 30 msec, see hci_core.c), and -the Marvell chip is known for its bad bt+wifi coexisting performance. - -So decrease that passive scan interval and make the scan window shorter -on this particular device to allow for spending more time transmitting -wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and -the new scan window is 6.25 msec (0xa * 0,625 msec). - -This change has a very large impact on the 2.4GHz wifi speeds and gets -it up to performance comparable with the Windows driver, which seems to -apply a similar quirk. - -The interval and window length were tested and found to work very well -with a lot of Bluetooth Low Energy devices, including the Surface Pen, a -Bluetooth Speaker and two modern Bluetooth headphones. All devices were -discovered immediately after turning them on. Even lower values were -also tested, but they introduced longer delays until devices get -discovered. - -Patchset: mwifiex ---- - drivers/bluetooth/btusb.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 11755cb1eb16..e69c6c9957a2 100644 ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; - #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) - #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) - #define BTUSB_ACTIONS_SEMI BIT(27) -+#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) - - static const struct usb_device_id btusb_table[] = { - /* Generic Bluetooth USB device */ -@@ -432,6 +433,7 @@ static const struct usb_device_id quirks_table[] = { - { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, - { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, - { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, -+ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, - - /* Intel Bluetooth devices */ - { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3837,6 +3839,19 @@ static int btusb_probe(struct usb_interface *intf, - if (id->driver_info & BTUSB_MARVELL) - hdev->set_bdaddr = btusb_set_bdaddr_marvell; - -+ /* The Marvell 88W8897 combined wifi and bluetooth card is known for -+ * very bad bt+wifi coexisting performance. -+ * -+ * Decrease the passive BT Low Energy scan interval a bit -+ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter -+ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly -+ * higher wifi throughput while passively scanning for BT LE devices. -+ */ -+ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { -+ hdev->le_scan_interval = 0x0190; -+ hdev->le_scan_window = 0x000a; -+ } -+ - if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && - (id->driver_info & BTUSB_MEDIATEK)) { - hdev->setup = btusb_mtk_setup; --- -2.47.1 - diff --git a/patches/6.14-rc4/0004-ath10k.patch b/patches/6.14-rc4/0004-ath10k.patch deleted file mode 100644 index e1e6253a8b..0000000000 --- a/patches/6.14-rc4/0004-ath10k.patch +++ /dev/null @@ -1,120 +0,0 @@ -From cc9a74a369def421de56b0581f6131c4cd15355d Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 27 Feb 2021 00:45:52 +0100 -Subject: [PATCH] ath10k: Add module parameters to override board files - -Some Surface devices, specifically the Surface Go and AMD version of the -Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better -with a different board file, as it seems that the firmeware included -upstream is buggy. - -As it is generally not a good idea to randomly overwrite files, let -alone doing so via packages, we add module parameters to override those -file names in the driver. This allows us to package/deploy the override -via a modprobe.d config. - -Signed-off-by: Maximilian Luz -Patchset: ath10k ---- - drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ - 1 file changed, 57 insertions(+) - -diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index b3294287bce1..2936fdae823c 100644 ---- a/drivers/net/wireless/ath/ath10k/core.c -+++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -40,6 +40,9 @@ static bool fw_diag_log; - /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ - unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; - -+static char *override_board = ""; -+static char *override_board2 = ""; -+ - unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | - BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); - -@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); - module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); - module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); - -+module_param(override_board, charp, 0644); -+module_param(override_board2, charp, 0644); -+ - MODULE_PARM_DESC(debug_mask, "Debugging mask"); - MODULE_PARM_DESC(uart_print, "Uart target debugging"); - MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); -@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, - MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); - MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); - -+MODULE_PARM_DESC(override_board, "Override for board.bin file"); -+MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); -+ - static const struct ath10k_hw_params ath10k_hw_params_list[] = { - { - .id = QCA988X_HW_2_0_VERSION, -@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) - return 0; - } - -+static const char *ath10k_override_board_fw_file(struct ath10k *ar, -+ const char *file) -+{ -+ if (strcmp(file, "board.bin") == 0) { -+ if (strcmp(override_board, "") == 0) -+ return file; -+ -+ if (strcmp(override_board, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); -+ return NULL; -+ } -+ -+ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", -+ override_board); -+ -+ return override_board; -+ } -+ -+ if (strcmp(file, "board-2.bin") == 0) { -+ if (strcmp(override_board2, "") == 0) -+ return file; -+ -+ if (strcmp(override_board2, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); -+ return NULL; -+ } -+ -+ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", -+ override_board2); -+ -+ return override_board2; -+ } -+ -+ return file; -+} -+ - static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - const char *dir, - const char *file) -@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - if (dir == NULL) - dir = "."; - -+ /* HACK: Override board.bin and board-2.bin files if specified. -+ * -+ * Some Surface devices perform better with a different board -+ * configuration. To this end, one would need to replace the board.bin -+ * file with the modified config and remove the board-2.bin file. -+ * Unfortunately, that's not a solution that we can easily package. So -+ * we add module options to perform these overrides here. -+ */ -+ file = ath10k_override_board_fw_file(ar, file); -+ if (!file) -+ return ERR_PTR(-ENOENT); -+ - if (ar->board_name) { - snprintf(filename, sizeof(filename), "%s/%s/%s", - dir, ar->board_name, file); --- -2.47.1 - diff --git a/patches/6.14-rc4/0005-ipts.patch b/patches/6.14-rc4/0005-ipts.patch deleted file mode 100644 index dd23c2ea1b..0000000000 --- a/patches/6.14-rc4/0005-ipts.patch +++ /dev/null @@ -1,3250 +0,0 @@ -From 3e89507b8f6c6d36e5bf587a74c65be5d9796ffd Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Thu, 30 Jul 2020 13:21:53 +0200 -Subject: [PATCH] mei: me: Add Icelake device ID for iTouch - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/misc/mei/hw-me-regs.h | 1 + - drivers/misc/mei/pci-me.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index c3a6657dcd4a..82eef2f4eb0a 100644 ---- a/drivers/misc/mei/hw-me-regs.h -+++ b/drivers/misc/mei/hw-me-regs.h -@@ -92,6 +92,7 @@ - #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ - - #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ -+#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ - #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ - - #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ -diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 6589635f8ba3..a1df48a434e2 100644 ---- a/drivers/misc/mei/pci-me.c -+++ b/drivers/misc/mei/pci-me.c -@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { - {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, -+ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, --- -2.47.1 - -From 1d6df5a556693e735cc78a603c29112a76ee883b Mon Sep 17 00:00:00 2001 -From: Liban Hannan -Date: Tue, 12 Apr 2022 23:31:12 +0100 -Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS - -Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. -Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: - -DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr -0x104ea3000 [fault reason 0x06] PTE Read access is not set - -This is very similar to the bug described at: -https://bugs.launchpad.net/bugs/1958004 - -Fixed with the following patch which this patch basically copies: -https://launchpadlibrarian.net/586396847/43255ca.diff - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index cc23cfcdeb2d..c010aebe6cc1 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -40,6 +40,11 @@ - #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) - #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) - -+#define IS_IPTS(pdev) ( \ -+ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ -+ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ -+ ) -+ - #define IOAPIC_RANGE_START (0xfee00000) - #define IOAPIC_RANGE_END (0xfeefffff) - #define IOVA_START_ADDR (0x1000) -@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); - int intel_iommu_enabled = 0; - EXPORT_SYMBOL_GPL(intel_iommu_enabled); - -+static int dmar_map_ipts = 1; - static int intel_iommu_superpage = 1; - static int iommu_identity_mapping; - static int iommu_skip_te_disable; - static int disable_igfx_iommu; - - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPTS 16 - - const struct iommu_ops intel_iommu_ops; - static const struct iommu_dirty_ops intel_dirty_ops; -@@ -2046,6 +2053,9 @@ static int device_def_domain_type(struct device *dev) - - if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) - return IOMMU_DOMAIN_IDENTITY; -+ -+ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; - } - - return 0; -@@ -2344,6 +2354,9 @@ static int __init init_dmars(void) - iommu_set_root_entry(iommu); - } - -+ if (!dmar_map_ipts) -+ iommu_identity_mapping |= IDENTMAP_IPTS; -+ - check_tylersburg_isoch(); - - /* -@@ -4651,6 +4664,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - disable_igfx_iommu = 1; - } - -+static void quirk_iommu_ipts(struct pci_dev *dev) -+{ -+ if (!IS_IPTS(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; -+ -+ pci_info(dev, "Disabling IOMMU for IPTS\n"); -+ dmar_map_ipts = 0; -+} -+ - /* G4x/GM45 integrated gfx dmar support is totally busted. */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4686,6 +4711,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); - -+/* disable IPTS dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -+ - static void quirk_iommu_rwbf(struct pci_dev *dev) - { - if (risky_device(dev)) --- -2.47.1 - -From e4e616d49f7a021b83cd0114f0642090e88a054f Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Sun, 11 Dec 2022 12:00:59 +0100 -Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus - -Based on linux-surface/intel-precise-touch@8abe268 - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 2 + - drivers/hid/ipts/Kconfig | 14 + - drivers/hid/ipts/Makefile | 16 ++ - drivers/hid/ipts/cmd.c | 61 +++++ - drivers/hid/ipts/cmd.h | 60 ++++ - drivers/hid/ipts/context.h | 52 ++++ - drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ - drivers/hid/ipts/control.h | 126 +++++++++ - drivers/hid/ipts/desc.h | 80 ++++++ - drivers/hid/ipts/eds1.c | 104 +++++++ - drivers/hid/ipts/eds1.h | 35 +++ - drivers/hid/ipts/eds2.c | 145 ++++++++++ - drivers/hid/ipts/eds2.h | 35 +++ - drivers/hid/ipts/hid.c | 225 +++++++++++++++ - drivers/hid/ipts/hid.h | 24 ++ - drivers/hid/ipts/main.c | 126 +++++++++ - drivers/hid/ipts/mei.c | 188 +++++++++++++ - drivers/hid/ipts/mei.h | 66 +++++ - drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ - drivers/hid/ipts/receiver.h | 16 ++ - drivers/hid/ipts/resources.c | 131 +++++++++ - drivers/hid/ipts/resources.h | 41 +++ - drivers/hid/ipts/spec-data.h | 100 +++++++ - drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ - drivers/hid/ipts/spec-hid.h | 34 +++ - drivers/hid/ipts/thread.c | 84 ++++++ - drivers/hid/ipts/thread.h | 59 ++++ - 28 files changed, 2853 insertions(+) - create mode 100644 drivers/hid/ipts/Kconfig - create mode 100644 drivers/hid/ipts/Makefile - create mode 100644 drivers/hid/ipts/cmd.c - create mode 100644 drivers/hid/ipts/cmd.h - create mode 100644 drivers/hid/ipts/context.h - create mode 100644 drivers/hid/ipts/control.c - create mode 100644 drivers/hid/ipts/control.h - create mode 100644 drivers/hid/ipts/desc.h - create mode 100644 drivers/hid/ipts/eds1.c - create mode 100644 drivers/hid/ipts/eds1.h - create mode 100644 drivers/hid/ipts/eds2.c - create mode 100644 drivers/hid/ipts/eds2.h - create mode 100644 drivers/hid/ipts/hid.c - create mode 100644 drivers/hid/ipts/hid.h - create mode 100644 drivers/hid/ipts/main.c - create mode 100644 drivers/hid/ipts/mei.c - create mode 100644 drivers/hid/ipts/mei.h - create mode 100644 drivers/hid/ipts/receiver.c - create mode 100644 drivers/hid/ipts/receiver.h - create mode 100644 drivers/hid/ipts/resources.c - create mode 100644 drivers/hid/ipts/resources.h - create mode 100644 drivers/hid/ipts/spec-data.h - create mode 100644 drivers/hid/ipts/spec-device.h - create mode 100644 drivers/hid/ipts/spec-hid.h - create mode 100644 drivers/hid/ipts/thread.c - create mode 100644 drivers/hid/ipts/thread.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index f8a56d631242..38eb29e4cc31 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1386,11 +1386,13 @@ source "drivers/hid/amd-sfh-hid/Kconfig" - source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/intel-thc-hid/Kconfig" - -+source "drivers/hid/ipts/Kconfig" -+ - endif # HID - - # USB support may be used with HID disabled - - source "drivers/hid/usbhid/Kconfig" - - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 496dab54c73a..02588e5d01eb 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -171,5 +171,7 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ - obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - - obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ -+ -+obj-$(CONFIG_HID_IPTS) += ipts/ -diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig -new file mode 100644 -index 000000000000..297401bd388d ---- /dev/null -+++ b/drivers/hid/ipts/Kconfig -@@ -0,0 +1,14 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+ -+config HID_IPTS -+ tristate "Intel Precise Touch & Stylus" -+ depends on INTEL_MEI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Precise Touch & Stylus (IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ipts. -diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile -new file mode 100644 -index 000000000000..883896f68e6a ---- /dev/null -+++ b/drivers/hid/ipts/Makefile -@@ -0,0 +1,16 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+# -+# Makefile for the IPTS touchscreen driver -+# -+ -+obj-$(CONFIG_HID_IPTS) += ipts.o -+ipts-objs := cmd.o -+ipts-objs += control.o -+ipts-objs += eds1.o -+ipts-objs += eds2.o -+ipts-objs += hid.o -+ipts-objs += main.o -+ipts-objs += mei.o -+ipts-objs += receiver.o -+ipts-objs += resources.o -+ipts-objs += thread.o -diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c -new file mode 100644 -index 000000000000..63a4934bbc5f ---- /dev/null -+++ b/drivers/hid/ipts/cmd.c -@@ -0,0 +1,61 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "mei.h" -+#include "spec-device.h" -+ -+int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp, u64 timeout) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!rsp) -+ return -EFAULT; -+ -+ /* -+ * In a response, the command code will have the most significant bit flipped to 1. -+ * If code is passed to ipts_mei_recv as is, no messages will be received. -+ */ -+ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); -+ if (ret < 0) -+ return ret; -+ -+ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); -+ -+ /* -+ * Some devices will always return this error. -+ * It is allowed to ignore it and to try continuing. -+ */ -+ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) -+ rsp->status = IPTS_STATUS_SUCCESS; -+ -+ return 0; -+} -+ -+int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) -+{ -+ struct ipts_command cmd = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.cmd = code; -+ -+ if (data && size > 0) -+ memcpy(cmd.payload, data, size); -+ -+ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); -+ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); -+} -diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h -new file mode 100644 -index 000000000000..2b4079075b64 ---- /dev/null -+++ b/drivers/hid/ipts/cmd.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CMD_H -+#define IPTS_CMD_H -+ -+#include -+ -+#include "context.h" -+#include "spec-device.h" -+ -+/* -+ * The default timeout for receiving responses -+ */ -+#define IPTS_CMD_DEFAULT_TIMEOUT 1000 -+ -+/** -+ * ipts_cmd_recv_timeout() - Receives a response to a command. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command / response. -+ * @rsp: The address that the received response will be copied to. -+ * @timeout: How many milliseconds the function will wait at most. -+ * -+ * A negative timeout means to wait forever. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp, u64 timeout); -+ -+/** -+ * ipts_cmd_recv() - Receives a response to a command. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command / response. -+ * @rsp: The address that the received response will be copied to. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp) -+{ -+ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); -+} -+ -+/** -+ * ipts_cmd_send() - Executes a command on the device. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command to execute. -+ * @data: The payload containing parameters for the command. -+ * @size: The size of the payload. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); -+ -+#endif /* IPTS_CMD_H */ -diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h -new file mode 100644 -index 000000000000..ba33259f1f7c ---- /dev/null -+++ b/drivers/hid/ipts/context.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CONTEXT_H -+#define IPTS_CONTEXT_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mei.h" -+#include "resources.h" -+#include "spec-device.h" -+#include "thread.h" -+ -+struct ipts_context { -+ struct device *dev; -+ struct ipts_mei mei; -+ -+ enum ipts_mode mode; -+ -+ /* -+ * Prevents concurrent GET_FEATURE reports. -+ */ -+ struct mutex feature_lock; -+ struct completion feature_event; -+ -+ /* -+ * These are not inside of struct ipts_resources -+ * because they don't own the memory they point to. -+ */ -+ struct ipts_buffer feature_report; -+ struct ipts_buffer descriptor; -+ -+ bool hid_active; -+ struct hid_device *hid; -+ -+ struct ipts_device_info info; -+ struct ipts_resources resources; -+ -+ struct ipts_thread receiver_loop; -+}; -+ -+#endif /* IPTS_CONTEXT_H */ -diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c -new file mode 100644 -index 000000000000..5360842d260b ---- /dev/null -+++ b/drivers/hid/ipts/control.c -@@ -0,0 +1,486 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "hid.h" -+#include "receiver.h" -+#include "resources.h" -+#include "spec-data.h" -+#include "spec-device.h" -+ -+static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!info) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ memcpy(info, rsp.payload, sizeof(*info)); -+ return 0; -+} -+ -+static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ struct ipts_set_mode cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.mode = mode; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) -+{ -+ int i = 0; -+ int ret = 0; -+ struct ipts_mem_window cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); -+ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); -+ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); -+ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); -+ } -+ -+ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); -+ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); -+ -+ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); -+ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); -+ -+ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); -+ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); -+ -+ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; -+ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+static int ipts_control_get_descriptor(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_data_header *header = NULL; -+ struct ipts_get_descriptor cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->resources.descriptor.address) -+ return -EFAULT; -+ -+ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); -+ -+ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); -+ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); -+ cmd.magic = 8; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ header = (struct ipts_data_header *)ipts->resources.descriptor.address; -+ -+ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { -+ ipts->descriptor.address = &header->data[8]; -+ ipts->descriptor.size = header->size - 8; -+ -+ return 0; -+ } -+ -+ return -ENODATA; -+} -+ -+int ipts_control_request_flush(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_quiesce_io cmd = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); -+ if (ret) -+ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_control_wait_flush(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status == IPTS_STATUS_TIMEOUT) -+ return -EAGAIN; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_request_data(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); -+ if (ret) -+ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!shutdown) -+ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); -+ else -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); -+ -+ if (ret) { -+ if (ret != -EAGAIN) -+ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); -+ -+ return ret; -+ } -+ -+ /* -+ * During shutdown, it is possible that the sensor has already been disabled. -+ */ -+ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) -+ return 0; -+ -+ if (rsp.status == IPTS_STATUS_TIMEOUT) -+ return -EAGAIN; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) -+{ -+ int ret = 0; -+ struct ipts_feedback cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.buffer = buffer; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * We don't know what feedback data looks like so we are sending zeros. -+ * See also ipts_control_refill_buffer. -+ */ -+ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) -+ return 0; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, -+ enum ipts_feedback_data_type type, void *data, size_t size) -+{ -+ struct ipts_feedback_header *header = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->resources.hid2me.address) -+ return -EFAULT; -+ -+ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); -+ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; -+ -+ header->cmd_type = cmd; -+ header->data_type = type; -+ header->size = size; -+ header->buffer = IPTS_HID2ME_BUFFER; -+ -+ if (size + sizeof(*header) > ipts->resources.hid2me.size) -+ return -EINVAL; -+ -+ if (data && size > 0) -+ memcpy(header->payload, data, size); -+ -+ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); -+} -+ -+int ipts_control_start(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_device_info info = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "Starting IPTS\n"); -+ -+ ret = ipts_control_get_device_info(ipts, &info); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); -+ return ret; -+ } -+ -+ ipts->info = info; -+ -+ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); -+ return ret; -+ } -+ -+ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); -+ -+ /* -+ * Handle newer devices -+ */ -+ if (info.intf_eds > 1) { -+ /* -+ * Fetching the descriptor will only work on newer devices. -+ * For older devices, a fallback descriptor will be used. -+ */ -+ ret = ipts_control_get_descriptor(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * Newer devices can be directly initialized in polling mode. -+ */ -+ ipts->mode = IPTS_MODE_POLL; -+ } -+ -+ ret = ipts_control_set_mode(ipts, ipts->mode); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_set_mem_window(ipts, &ipts->resources); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_receiver_start(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_request_data(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request data: %d\n", ret); -+ return ret; -+ } -+ -+ ipts_hid_enable(ipts); -+ -+ ret = ipts_hid_init(ipts, info); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int _ipts_control_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ipts_hid_disable(ipts); -+ dev_info(ipts->dev, "Stopping IPTS\n"); -+ -+ ret = ipts_receiver_stop(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_resources_free(&ipts->resources); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ ret = _ipts_control_stop(ipts); -+ if (ret) -+ return ret; -+ -+ ret = ipts_hid_free(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_restart(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ ret = _ipts_control_stop(ipts); -+ if (ret) -+ return ret; -+ -+ /* -+ * Wait a second to give the sensor time to fully shut down. -+ */ -+ msleep(1000); -+ -+ ret = ipts_control_start(ipts); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h -new file mode 100644 -index 000000000000..26629c5144ed ---- /dev/null -+++ b/drivers/hid/ipts/control.h -@@ -0,0 +1,126 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CONTROL_H -+#define IPTS_CONTROL_H -+ -+#include -+ -+#include "context.h" -+#include "spec-data.h" -+#include "spec-device.h" -+ -+/** -+ * ipts_control_request_flush() - Stop the data flow. -+ * @ipts: The IPTS driver context. -+ * -+ * Runs the command to stop the data flow on the device. -+ * All outstanding data needs to be acknowledged using feedback before the command will return. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_request_flush(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_flush() - Wait until data flow has been stopped. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_wait_flush(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_request_data(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_data() - Wait until new data is available. -+ * @ipts: The IPTS driver context. -+ * @block: Whether to block execution until data is available. -+ * -+ * In poll mode, this function will never return while the data flow is active. Instead, -+ * the poll will be incremented when new data is available. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. -+ */ -+int ipts_control_wait_data(struct ipts_context *ipts, bool block); -+ -+/** -+ * ipts_control_send_feedback() - Submits a feedback buffer to the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The ID of the buffer containing feedback data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); -+ -+/** -+ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. -+ * @ipts: The IPTS driver context. -+ * @cmd: The command that will be run on the device. -+ * @type: The type of the payload that is sent to the device. -+ * @data: The payload of the feedback command. -+ * @size: The size of the payload. -+ * -+ * HID2ME feedback is a special type of feedback, because it allows interfacing with -+ * the HID API of the device at any moment, without requiring a buffer that has to -+ * be acknowledged. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, -+ enum ipts_feedback_data_type type, void *data, size_t size); -+ -+/** -+ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer that has been processed and can be refilled. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) -+{ -+ /* -+ * IPTS expects structured data in the feedback buffer matching the buffer that will be -+ * refilled. We don't know what that data looks like, so we just keep the buffer empty. -+ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. -+ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling -+ * the buffers on some devices. -+ */ -+ -+ return ipts_control_send_feedback(ipts, buffer); -+} -+ -+/** -+ * ipts_control_start() - Initialized the device and starts the data flow. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_start(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_stop() - Stops the data flow and resets the device. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_stop(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_restart() - Stops the device and starts it again. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_restart(struct ipts_context *ipts); -+ -+#endif /* IPTS_CONTROL_H */ -diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h -new file mode 100644 -index 000000000000..307438c7c80c ---- /dev/null -+++ b/drivers/hid/ipts/desc.h -@@ -0,0 +1,80 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_DESC_H -+#define IPTS_DESC_H -+ -+#include -+ -+#define IPTS_HID_REPORT_SINGLETOUCH 64 -+#define IPTS_HID_REPORT_DATA 65 -+#define IPTS_HID_REPORT_SET_MODE 66 -+ -+#define IPTS_HID_REPORT_DATA_SIZE 7485 -+ -+/* -+ * HID descriptor for singletouch data. -+ * This descriptor should be present on all IPTS devices. -+ */ -+static const u8 ipts_singletouch_descriptor[] = { -+ 0x05, 0x0D, /* Usage Page (Digitizer), */ -+ 0x09, 0x04, /* Usage (Touchscreen), */ -+ 0xA1, 0x01, /* Collection (Application), */ -+ 0x85, 0x40, /* Report ID (64), */ -+ 0x09, 0x42, /* Usage (Tip Switch), */ -+ 0x15, 0x00, /* Logical Minimum (0), */ -+ 0x25, 0x01, /* Logical Maximum (1), */ -+ 0x75, 0x01, /* Report Size (1), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x95, 0x07, /* Report Count (7), */ -+ 0x81, 0x03, /* Input (Constant, Variable), */ -+ 0x05, 0x01, /* Usage Page (Desktop), */ -+ 0x09, 0x30, /* Usage (X), */ -+ 0x75, 0x10, /* Report Size (16), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0xA4, /* Push, */ -+ 0x55, 0x0E, /* Unit Exponent (14), */ -+ 0x65, 0x11, /* Unit (Centimeter), */ -+ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ -+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x09, 0x31, /* Usage (Y), */ -+ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ -+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0xB4, /* Pop, */ -+ 0xC0, /* End Collection */ -+}; -+ -+/* -+ * Fallback HID descriptor for older devices that do not have -+ * the ability to query their HID descriptor. -+ */ -+static const u8 ipts_fallback_descriptor[] = { -+ 0x05, 0x0D, /* Usage Page (Digitizer), */ -+ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ -+ 0xA1, 0x01, /* Collection (Application), */ -+ 0x85, 0x41, /* Report ID (65), */ -+ 0x09, 0x56, /* Usage (Scan Time), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0x75, 0x10, /* Report Size (16), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x09, 0x61, /* Usage (Gesture Char Quality), */ -+ 0x75, 0x08, /* Report Size (8), */ -+ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ -+ 0x81, 0x03, /* Input (Constant, Variable), */ -+ 0x85, 0x42, /* Report ID (66), */ -+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ -+ 0x09, 0xC8, /* Usage (C8h), */ -+ 0x75, 0x08, /* Report Size (8), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0xB1, 0x02, /* Feature (Variable), */ -+ 0xC0, /* End Collection, */ -+}; -+ -+#endif /* IPTS_DESC_H */ -diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c -new file mode 100644 -index 000000000000..7b9f54388a9f ---- /dev/null -+++ b/drivers/hid/ipts/eds1.c -@@ -0,0 +1,104 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "eds1.h" -+#include "spec-device.h" -+ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, -+ sizeof(ipts_fallback_descriptor)); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == mode) -+ return 0; -+ -+ ipts->mode = mode; -+ -+ ret = ipts_control_restart(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_id != IPTS_HID_REPORT_SET_MODE) -+ return -EIO; -+ -+ if (report_type != HID_FEATURE_REPORT) -+ return -EIO; -+ -+ if (size != 2) -+ return -EINVAL; -+ -+ /* -+ * Implement mode switching report for older devices without native HID support. -+ */ -+ -+ if (request_type == HID_REQ_GET_REPORT) { -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ buffer[1] = ipts->mode; -+ } else if (request_type == HID_REQ_SET_REPORT) { -+ return ipts_eds1_switch_mode(ipts, buffer[1]); -+ } else { -+ return -EIO; -+ } -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h -new file mode 100644 -index 000000000000..eeeb6575e3e8 ---- /dev/null -+++ b/drivers/hid/ipts/eds1.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "context.h" -+ -+/** -+ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds1_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type); -diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c -new file mode 100644 -index 000000000000..639940794615 ---- /dev/null -+++ b/drivers/hid/ipts/eds2.c -@@ -0,0 +1,145 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "eds2.h" -+#include "spec-data.h" -+ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, -+ ipts->descriptor.size); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ mutex_lock(&ipts->feature_lock); -+ -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ -+ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); -+ reinit_completion(&ipts->feature_event); -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ goto out; -+ } -+ -+ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); -+ if (ret == 0) { -+ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ if (!ipts->feature_report.address) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (ipts->feature_report.size > size) { -+ ret = -ETOOSMALL; -+ goto out; -+ } -+ -+ ret = ipts->feature_report.size; -+ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); -+ -+out: -+ mutex_unlock(&ipts->feature_lock); -+ return ret; -+} -+ -+static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ buffer[0] = report_id; -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; -+ else -+ return -EIO; -+ -+ if (request_type == HID_REQ_GET_REPORT) -+ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); -+ else -+ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); -+} -diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h -new file mode 100644 -index 000000000000..064e3716907a ---- /dev/null -+++ b/drivers/hid/ipts/eds2.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "context.h" -+ -+/** -+ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds2_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type); -diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c -new file mode 100644 -index 000000000000..e34a1a4f9fa7 ---- /dev/null -+++ b/drivers/hid/ipts/hid.c -@@ -0,0 +1,225 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "desc.h" -+#include "eds1.h" -+#include "eds2.h" -+#include "hid.h" -+#include "spec-data.h" -+#include "spec-hid.h" -+ -+void ipts_hid_enable(struct ipts_context *ipts) -+{ -+ WRITE_ONCE(ipts->hid_active, true); -+} -+ -+void ipts_hid_disable(struct ipts_context *ipts) -+{ -+ WRITE_ONCE(ipts->hid_active, false); -+} -+ -+static int ipts_hid_start(struct hid_device *hid) -+{ -+ return 0; -+} -+ -+static void ipts_hid_stop(struct hid_device *hid) -+{ -+} -+ -+static int ipts_hid_parse(struct hid_device *hid) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ u8 *buffer = NULL; -+ size_t size = 0; -+ -+ if (!hid) -+ return -ENODEV; -+ -+ ipts = hid->driver_data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ if (ipts->info.intf_eds == 1) -+ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); -+ else -+ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ ret = hid_parse_report(hid, buffer, size); -+ kfree(buffer); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, -+ size_t size, unsigned char report_type, int request_type) -+{ -+ struct ipts_context *ipts = NULL; -+ -+ if (!hid) -+ return -ENODEV; -+ -+ ipts = hid->driver_data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ if (ipts->info.intf_eds == 1) { -+ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } else { -+ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } -+} -+ -+static struct hid_ll_driver ipts_hid_driver = { -+ .start = ipts_hid_start, -+ .stop = ipts_hid_stop, -+ .open = ipts_hid_start, -+ .close = ipts_hid_stop, -+ .parse = ipts_hid_parse, -+ .raw_request = ipts_hid_raw_request, -+}; -+ -+int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) -+{ -+ u8 *temp = NULL; -+ struct ipts_hid_header *frame = NULL; -+ struct ipts_data_header *header = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->hid) -+ return -ENODEV; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; -+ -+ temp = ipts->resources.report.address; -+ memset(temp, 0, ipts->resources.report.size); -+ -+ if (!header) -+ return -EFAULT; -+ -+ if (header->size == 0) -+ return 0; -+ -+ if (header->type == IPTS_DATA_TYPE_HID) -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); -+ -+ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { -+ ipts->feature_report.address = header->data; -+ ipts->feature_report.size = header->size; -+ -+ complete_all(&ipts->feature_event); -+ return 0; -+ } -+ -+ if (header->type != IPTS_DATA_TYPE_FRAME) -+ return 0; -+ -+ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) -+ return -ERANGE; -+ -+ /* -+ * Synthesize a HID report matching the devices that natively send HID reports -+ */ -+ temp[0] = IPTS_HID_REPORT_DATA; -+ -+ frame = (struct ipts_hid_header *)&temp[3]; -+ frame->type = IPTS_HID_FRAME_TYPE_RAW; -+ frame->size = header->size + sizeof(*frame); -+ -+ memcpy(frame->data, header->data, header->size); -+ -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); -+} -+ -+int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->hid) -+ return 0; -+ -+ ipts->hid = hid_allocate_device(); -+ if (IS_ERR(ipts->hid)) { -+ int err = PTR_ERR(ipts->hid); -+ -+ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); -+ return err; -+ } -+ -+ ipts->hid->driver_data = ipts; -+ ipts->hid->dev.parent = ipts->dev; -+ ipts->hid->ll_driver = &ipts_hid_driver; -+ -+ ipts->hid->vendor = info.vendor; -+ ipts->hid->product = info.product; -+ ipts->hid->group = HID_GROUP_GENERIC; -+ -+ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, -+ info.product); -+ -+ ret = hid_add_device(ipts->hid); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); -+ ipts_hid_free(ipts); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_hid_free(struct ipts_context *ipts) -+{ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->hid) -+ return 0; -+ -+ hid_destroy_device(ipts->hid); -+ ipts->hid = NULL; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h -new file mode 100644 -index 000000000000..1ebe77447903 ---- /dev/null -+++ b/drivers/hid/ipts/hid.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_HID_H -+#define IPTS_HID_H -+ -+#include -+ -+#include "context.h" -+#include "spec-device.h" -+ -+void ipts_hid_enable(struct ipts_context *ipts); -+void ipts_hid_disable(struct ipts_context *ipts); -+ -+int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); -+ -+int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); -+int ipts_hid_free(struct ipts_context *ipts); -+ -+#endif /* IPTS_HID_H */ -diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c -new file mode 100644 -index 000000000000..fb5b5c13ee3e ---- /dev/null -+++ b/drivers/hid/ipts/main.c -@@ -0,0 +1,126 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "mei.h" -+#include "receiver.h" -+#include "spec-device.h" -+ -+/* -+ * The MEI client ID for IPTS functionality. -+ */ -+#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) -+ -+static int ipts_set_dma_mask(struct mei_cl_device *cldev) -+{ -+ if (!cldev) -+ return -EFAULT; -+ -+ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) -+ return 0; -+ -+ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); -+} -+ -+static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) -+ return -EFAULT; -+ -+ ret = ipts_set_dma_mask(cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mei_cldev_enable(cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); -+ return ret; -+ } -+ -+ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); -+ if (!ipts) { -+ mei_cldev_disable(cldev); -+ return -ENOMEM; -+ } -+ -+ ret = ipts_mei_init(&ipts->mei, cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); -+ return ret; -+ } -+ -+ ipts->dev = &cldev->dev; -+ ipts->mode = IPTS_MODE_EVENT; -+ -+ mutex_init(&ipts->feature_lock); -+ init_completion(&ipts->feature_event); -+ -+ mei_cldev_set_drvdata(cldev, ipts); -+ -+ ret = ipts_control_start(ipts); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void ipts_remove(struct mei_cl_device *cldev) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) { -+ pr_err("MEI device is NULL!"); -+ return; -+ } -+ -+ ipts = mei_cldev_get_drvdata(cldev); -+ -+ ret = ipts_control_stop(ipts); -+ if (ret) -+ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); -+ -+ mei_cldev_disable(cldev); -+} -+ -+static struct mei_cl_device_id ipts_device_id_table[] = { -+ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(mei, ipts_device_id_table); -+ -+static struct mei_cl_driver ipts_driver = { -+ .id_table = ipts_device_id_table, -+ .name = "ipts", -+ .probe = ipts_probe, -+ .remove = ipts_remove, -+}; -+module_mei_cl_driver(ipts_driver); -+ -+MODULE_DESCRIPTION("IPTS touchscreen driver"); -+MODULE_AUTHOR("Dorian Stoll "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c -new file mode 100644 -index 000000000000..1e0395ceae4a ---- /dev/null -+++ b/drivers/hid/ipts/mei.c -@@ -0,0 +1,188 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "mei.h" -+ -+static void locked_list_add(struct list_head *new, struct list_head *head, -+ struct rw_semaphore *lock) -+{ -+ down_write(lock); -+ list_add(new, head); -+ up_write(lock); -+} -+ -+static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) -+{ -+ down_write(lock); -+ list_del(entry); -+ up_write(lock); -+} -+ -+static void ipts_mei_incoming(struct mei_cl_device *cldev) -+{ -+ ssize_t ret = 0; -+ struct ipts_mei_message *entry = NULL; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) { -+ pr_err("MEI device is NULL!"); -+ return; -+ } -+ -+ ipts = mei_cldev_get_drvdata(cldev); -+ if (!ipts) { -+ pr_err("IPTS driver context is NULL!"); -+ return; -+ } -+ -+ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); -+ if (!entry) -+ return; -+ -+ INIT_LIST_HEAD(&entry->list); -+ -+ do { -+ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); -+ } while (ret == -EINTR); -+ -+ if (ret < 0) { -+ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); -+ return; -+ } -+ -+ if (ret == 0) { -+ dev_err(ipts->dev, "Received empty response\n"); -+ return; -+ } -+ -+ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); -+ wake_up_all(&ipts->mei.message_queue); -+} -+ -+static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, -+ struct ipts_response *rsp) -+{ -+ struct ipts_mei_message *entry = NULL; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!rsp) -+ return -EFAULT; -+ -+ down_read(&mei->message_lock); -+ -+ /* -+ * Iterate over the list of received messages, and check if there is one -+ * matching the requested command code. -+ */ -+ list_for_each_entry(entry, &mei->messages, list) { -+ if (entry->rsp.cmd == code) -+ break; -+ } -+ -+ up_read(&mei->message_lock); -+ -+ /* -+ * If entry is not the list head, this means that the loop above has been stopped early, -+ * and that we found a matching element. We drop the message from the list and return it. -+ */ -+ if (!list_entry_is_head(entry, &mei->messages, list)) { -+ locked_list_del(&entry->list, &mei->message_lock); -+ -+ *rsp = entry->rsp; -+ devm_kfree(&mei->cldev->dev, entry); -+ -+ return 0; -+ } -+ -+ return -EAGAIN; -+} -+ -+int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, -+ u64 timeout) -+{ -+ int ret = 0; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ /* -+ * A timeout of 0 means check and return immideately. -+ */ -+ if (timeout == 0) -+ return ipts_mei_search(mei, code, rsp); -+ -+ /* -+ * A timeout of less than 0 means to wait forever. -+ */ -+ if (timeout < 0) { -+ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); -+ return 0; -+ } -+ -+ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, -+ msecs_to_jiffies(timeout)); -+ -+ if (ret > 0) -+ return 0; -+ -+ return -EAGAIN; -+} -+ -+int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) -+{ -+ int ret = 0; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!mei->cldev) -+ return -EFAULT; -+ -+ if (!data) -+ return -EFAULT; -+ -+ do { -+ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); -+ } while (ret == -EINTR); -+ -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) -+{ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!cldev) -+ return -EFAULT; -+ -+ mei->cldev = cldev; -+ -+ INIT_LIST_HEAD(&mei->messages); -+ init_waitqueue_head(&mei->message_queue); -+ init_rwsem(&mei->message_lock); -+ -+ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h -new file mode 100644 -index 000000000000..973bade6b0fd ---- /dev/null -+++ b/drivers/hid/ipts/mei.h -@@ -0,0 +1,66 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_MEI_H -+#define IPTS_MEI_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "spec-device.h" -+ -+struct ipts_mei_message { -+ struct list_head list; -+ struct ipts_response rsp; -+}; -+ -+struct ipts_mei { -+ struct mei_cl_device *cldev; -+ -+ struct list_head messages; -+ -+ wait_queue_head_t message_queue; -+ struct rw_semaphore message_lock; -+}; -+ -+/** -+ * ipts_mei_recv() - Receive data from a MEI device. -+ * @mei: The IPTS MEI device context. -+ * @code: The IPTS command code to look for. -+ * @rsp: The address that the received data will be copied to. -+ * @timeout: How many milliseconds the function will wait at most. -+ * -+ * A negative timeout means to wait forever. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, -+ u64 timeout); -+ -+/** -+ * ipts_mei_send() - Send data to a MEI device. -+ * @ipts: The IPTS MEI device context. -+ * @data: The data to send. -+ * @size: The size of the data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); -+ -+/** -+ * ipts_mei_init() - Initialize the MEI device context. -+ * @mei: The MEI device context to initialize. -+ * @cldev: The MEI device the context will be bound to. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); -+ -+#endif /* IPTS_MEI_H */ -diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -new file mode 100644 -index 000000000000..977724c728c3 ---- /dev/null -+++ b/drivers/hid/ipts/receiver.c -@@ -0,0 +1,251 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "control.h" -+#include "hid.h" -+#include "receiver.h" -+#include "resources.h" -+#include "spec-device.h" -+#include "thread.h" -+ -+static void ipts_receiver_next_doorbell(struct ipts_context *ipts) -+{ -+ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; -+ *doorbell = *doorbell + 1; -+} -+ -+static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) -+{ -+ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; -+ return *doorbell; -+} -+ -+static void ipts_receiver_backoff(time64_t last, u32 n) -+{ -+ /* -+ * If the last change was less than n seconds ago, -+ * sleep for a shorter period so that new data can be -+ * processed quickly. If there was no change for more than -+ * n seconds, sleep longer to avoid wasting CPU cycles. -+ */ -+ if (last + n > ktime_get_seconds()) -+ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); -+ else -+ msleep(200); -+} -+ -+static int ipts_receiver_event_loop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ u32 buffer = 0; -+ -+ struct ipts_context *ipts = NULL; -+ time64_t last = ktime_get_seconds(); -+ -+ if (!thread) -+ return -EFAULT; -+ -+ ipts = thread->data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "IPTS running in event mode\n"); -+ -+ while (!ipts_thread_should_stop(thread)) { -+ int i = 0; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_control_wait_data(ipts, false); -+ if (ret == -EAGAIN) -+ break; -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ continue; -+ } -+ -+ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; -+ ipts_receiver_next_doorbell(ipts); -+ -+ ret = ipts_hid_input_data(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); -+ -+ ret = ipts_control_refill_buffer(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); -+ -+ ret = ipts_control_request_data(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to request data: %d\n", ret); -+ -+ last = ktime_get_seconds(); -+ } -+ -+ ipts_receiver_backoff(last, 5); -+ } -+ -+ ret = ipts_control_request_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_wait_data(ipts, true); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ ret = ipts_control_wait_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ return 0; -+} -+ -+static int ipts_receiver_poll_loop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ u32 buffer = 0; -+ -+ u32 doorbell = 0; -+ u32 lastdb = 0; -+ -+ struct ipts_context *ipts = NULL; -+ time64_t last = ktime_get_seconds(); -+ -+ if (!thread) -+ return -EFAULT; -+ -+ ipts = thread->data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "IPTS running in poll mode\n"); -+ -+ while (true) { -+ if (ipts_thread_should_stop(thread)) { -+ ret = ipts_control_request_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ doorbell = ipts_receiver_current_doorbell(ipts); -+ -+ /* -+ * After filling up one of the data buffers, IPTS will increment -+ * the doorbell. The value of the doorbell stands for the *next* -+ * buffer that IPTS is going to fill. -+ */ -+ while (lastdb != doorbell) { -+ buffer = lastdb % IPTS_BUFFERS; -+ -+ ret = ipts_hid_input_data(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); -+ -+ ret = ipts_control_refill_buffer(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); -+ -+ last = ktime_get_seconds(); -+ lastdb++; -+ } -+ -+ if (ipts_thread_should_stop(thread)) -+ break; -+ -+ ipts_receiver_backoff(last, 5); -+ } -+ -+ ret = ipts_control_wait_data(ipts, true); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ ret = ipts_control_wait_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ return 0; -+} -+ -+int ipts_receiver_start(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == IPTS_MODE_EVENT) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, -+ "ipts_event"); -+ } else if (ipts->mode == IPTS_MODE_POLL) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, -+ "ipts_poll"); -+ } else { -+ ret = -EINVAL; -+ } -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_receiver_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_thread_stop(&ipts->receiver_loop); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h -new file mode 100644 -index 000000000000..3de7da62d40c ---- /dev/null -+++ b/drivers/hid/ipts/receiver.h -@@ -0,0 +1,16 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_RECEIVER_H -+#define IPTS_RECEIVER_H -+ -+#include "context.h" -+ -+int ipts_receiver_start(struct ipts_context *ipts); -+int ipts_receiver_stop(struct ipts_context *ipts); -+ -+#endif /* IPTS_RECEIVER_H */ -diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c -new file mode 100644 -index 000000000000..cc14653b2a9f ---- /dev/null -+++ b/drivers/hid/ipts/resources.c -@@ -0,0 +1,131 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+ -+#include "desc.h" -+#include "resources.h" -+#include "spec-device.h" -+ -+static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) -+{ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (buffer->address) -+ return 0; -+ -+ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); -+ -+ if (!buffer->address) -+ return -ENOMEM; -+ -+ buffer->size = size; -+ buffer->device = dev; -+ -+ return 0; -+} -+ -+static void ipts_resources_free_buffer(struct ipts_buffer *buffer) -+{ -+ if (!buffer->address) -+ return; -+ -+ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); -+ -+ buffer->address = NULL; -+ buffer->size = 0; -+ -+ buffer->dma_address = 0; -+ buffer->device = NULL; -+} -+ -+int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) -+{ -+ int ret = 0; -+ -+ /* -+ * Some compilers (AOSP clang) complain about a redefined -+ * variable when this is declared inside of the for loop. -+ */ -+ int i = 0; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); -+ if (ret) -+ goto err; -+ } -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); -+ if (ret) -+ goto err; -+ } -+ -+ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); -+ if (ret) -+ goto err; -+ -+ if (!res->report.address) { -+ res->report.size = IPTS_HID_REPORT_DATA_SIZE; -+ res->report.address = kzalloc(res->report.size, GFP_KERNEL); -+ -+ if (!res->report.address) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } -+ -+ return 0; -+ -+err: -+ -+ ipts_resources_free(res); -+ return ret; -+} -+ -+int ipts_resources_free(struct ipts_resources *res) -+{ -+ int i = 0; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) -+ ipts_resources_free_buffer(&res->data[i]); -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) -+ ipts_resources_free_buffer(&res->feedback[i]); -+ -+ ipts_resources_free_buffer(&res->doorbell); -+ ipts_resources_free_buffer(&res->workqueue); -+ ipts_resources_free_buffer(&res->hid2me); -+ ipts_resources_free_buffer(&res->descriptor); -+ -+ kfree(res->report.address); -+ res->report.address = NULL; -+ res->report.size = 0; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h -new file mode 100644 -index 000000000000..2068e13285f0 ---- /dev/null -+++ b/drivers/hid/ipts/resources.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_RESOURCES_H -+#define IPTS_RESOURCES_H -+ -+#include -+#include -+ -+#include "spec-device.h" -+ -+struct ipts_buffer { -+ u8 *address; -+ size_t size; -+ -+ dma_addr_t dma_address; -+ struct device *device; -+}; -+ -+struct ipts_resources { -+ struct ipts_buffer data[IPTS_BUFFERS]; -+ struct ipts_buffer feedback[IPTS_BUFFERS]; -+ -+ struct ipts_buffer doorbell; -+ struct ipts_buffer workqueue; -+ struct ipts_buffer hid2me; -+ -+ struct ipts_buffer descriptor; -+ -+ // Buffer for synthesizing HID reports -+ struct ipts_buffer report; -+}; -+ -+int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); -+int ipts_resources_free(struct ipts_resources *res); -+ -+#endif /* IPTS_RESOURCES_H */ -diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h -new file mode 100644 -index 000000000000..e8dd98895a7e ---- /dev/null -+++ b/drivers/hid/ipts/spec-data.h -@@ -0,0 +1,100 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_DATA_H -+#define IPTS_SPEC_DATA_H -+ -+#include -+#include -+ -+/** -+ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. -+ */ -+enum ipts_feedback_cmd_type { -+ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, -+ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, -+ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, -+}; -+ -+/** -+ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. -+ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. -+ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. -+ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. -+ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. -+ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. -+ */ -+enum ipts_feedback_data_type { -+ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, -+ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, -+ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, -+ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, -+ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, -+}; -+ -+/** -+ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. -+ * @cmd_type: A command that should be executed on the sensor. -+ * @size: The size of the payload to be written. -+ * @buffer: The ID of the buffer that contains this feedback data. -+ * @protocol: The protocol version of the EDS. -+ * @data_type: The type of data that the buffer contains. -+ * @spi_offset: The offset at which to write the payload data to the sensor. -+ * @payload: Payload for the feedback command, or 0 if no payload is sent. -+ */ -+struct ipts_feedback_header { -+ enum ipts_feedback_cmd_type cmd_type; -+ u32 size; -+ u32 buffer; -+ u32 protocol; -+ enum ipts_feedback_data_type data_type; -+ u32 spi_offset; -+ u8 reserved[40]; -+ u8 payload[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_feedback_header) == 64); -+ -+/** -+ * enum ipts_data_type - Defines what type of data a buffer contains. -+ * @IPTS_DATA_TYPE_FRAME: Raw data frame. -+ * @IPTS_DATA_TYPE_ERROR: Error data. -+ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. -+ * @IPTS_DATA_TYPE_HID: A HID report. -+ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. -+ */ -+enum ipts_data_type { -+ IPTS_DATA_TYPE_FRAME = 0x00, -+ IPTS_DATA_TYPE_ERROR = 0x01, -+ IPTS_DATA_TYPE_VENDOR = 0x02, -+ IPTS_DATA_TYPE_HID = 0x03, -+ IPTS_DATA_TYPE_GET_FEATURES = 0x04, -+ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, -+}; -+ -+/** -+ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. -+ * @type: What data the buffer contains. -+ * @size: How much data the buffer contains. -+ * @buffer: Which buffer the data is in. -+ */ -+struct ipts_data_header { -+ enum ipts_data_type type; -+ u32 size; -+ u32 buffer; -+ u8 reserved[52]; -+ u8 data[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_data_header) == 64); -+ -+#endif /* IPTS_SPEC_DATA_H */ -diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h -new file mode 100644 -index 000000000000..41845f9d9025 ---- /dev/null -+++ b/drivers/hid/ipts/spec-device.h -@@ -0,0 +1,290 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_DEVICE_H -+#define IPTS_SPEC_DEVICE_H -+ -+#include -+#include -+ -+/* -+ * The amount of buffers that IPTS can use for data transfer. -+ */ -+#define IPTS_BUFFERS 16 -+ -+/* -+ * The buffer ID that is used for HID2ME feedback -+ */ -+#define IPTS_HID2ME_BUFFER IPTS_BUFFERS -+ -+/** -+ * enum ipts_command - Commands that can be sent to the IPTS hardware. -+ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. -+ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. -+ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. -+ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. -+ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. -+ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. -+ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. -+ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. -+ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. -+ */ -+enum ipts_command_code { -+ IPTS_CMD_GET_DEVICE_INFO = 0x01, -+ IPTS_CMD_SET_MODE = 0x02, -+ IPTS_CMD_SET_MEM_WINDOW = 0x03, -+ IPTS_CMD_QUIESCE_IO = 0x04, -+ IPTS_CMD_READY_FOR_DATA = 0x05, -+ IPTS_CMD_FEEDBACK = 0x06, -+ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, -+ IPTS_CMD_RESET_SENSOR = 0x0B, -+ IPTS_CMD_GET_DESCRIPTOR = 0x0F, -+}; -+ -+/** -+ * enum ipts_status - Possible status codes returned by the IPTS device. -+ * @IPTS_STATUS_SUCCESS: Operation completed successfully. -+ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. -+ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. -+ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. -+ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. -+ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. -+ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. -+ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. -+ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. -+ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. -+ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. -+ * The host can ignore this error and attempt to continue. -+ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. -+ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. -+ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. -+ * @IPTS_STATUS_TIMEOUT: The operation timed out. -+ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. -+ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. -+ * Further progress is not possible. -+ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. -+ * The driver can attempt to continue. -+ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. -+ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. -+ */ -+enum ipts_status { -+ IPTS_STATUS_SUCCESS = 0x00, -+ IPTS_STATUS_INVALID_PARAMS = 0x01, -+ IPTS_STATUS_ACCESS_DENIED = 0x02, -+ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, -+ IPTS_STATUS_NOT_READY = 0x04, -+ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, -+ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, -+ IPTS_STATUS_OUT_OF_MEMORY = 0x07, -+ IPTS_STATUS_INTERNAL_ERROR = 0x08, -+ IPTS_STATUS_SENSOR_DISABLED = 0x09, -+ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, -+ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, -+ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, -+ IPTS_STATUS_RESET_FAILED = 0x0D, -+ IPTS_STATUS_TIMEOUT = 0x0E, -+ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, -+ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, -+ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, -+ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, -+ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, -+}; -+ -+/** -+ * struct ipts_command - Message that is sent to the device for calling a command. -+ * @cmd: The command that will be called. -+ * @payload: Payload containing parameters for the called command. -+ */ -+struct ipts_command { -+ enum ipts_command_code cmd; -+ u8 payload[320]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_command) == 324); -+ -+/** -+ * enum ipts_mode - Configures what data the device produces and how its sent. -+ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. -+ * Older devices will return singletouch data in this mode. -+ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. -+ * Older devices will return multitouch data in this mode. -+ */ -+enum ipts_mode { -+ IPTS_MODE_EVENT = 0x00, -+ IPTS_MODE_POLL = 0x01, -+}; -+ -+/** -+ * struct ipts_set_mode - Payload for the SET_MODE command. -+ * @mode: Changes the mode that IPTS will operate in. -+ */ -+struct ipts_set_mode { -+ enum ipts_mode mode; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_set_mode) == 16); -+ -+#define IPTS_WORKQUEUE_SIZE 8192 -+#define IPTS_WORKQUEUE_ITEM_SIZE 16 -+ -+/** -+ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. -+ * @data_addr_lower: Lower 32 bits of the data buffer addresses. -+ * @data_addr_upper: Upper 32 bits of the data buffer addresses. -+ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. -+ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. -+ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. -+ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. -+ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. -+ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. -+ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. -+ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. -+ * @hid2me_size: Size of the hid2me feedback buffer. -+ * @workqueue_item_size: Magic value. Must be 16. -+ * @workqueue_size: Magic value. Must be 8192. -+ * -+ * The workqueue related items in this struct are required for using -+ * GuC submission with binary processing firmware. Since this driver does -+ * not use GuC submission and instead exports raw data to userspace, these -+ * items are not actually used, but they need to be allocated and passed -+ * to the device, otherwise initialization will fail. -+ */ -+struct ipts_mem_window { -+ u32 data_addr_lower[IPTS_BUFFERS]; -+ u32 data_addr_upper[IPTS_BUFFERS]; -+ u32 workqueue_addr_lower; -+ u32 workqueue_addr_upper; -+ u32 doorbell_addr_lower; -+ u32 doorbell_addr_upper; -+ u32 feedback_addr_lower[IPTS_BUFFERS]; -+ u32 feedback_addr_upper[IPTS_BUFFERS]; -+ u32 hid2me_addr_lower; -+ u32 hid2me_addr_upper; -+ u32 hid2me_size; -+ u8 reserved1; -+ u8 workqueue_item_size; -+ u16 workqueue_size; -+ u8 reserved[32]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_mem_window) == 320); -+ -+/** -+ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. -+ */ -+struct ipts_quiesce_io { -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_quiesce_io) == 12); -+ -+/** -+ * struct ipts_feedback - Payload for the FEEDBACK command. -+ * @buffer: The buffer that the device should refill. -+ */ -+struct ipts_feedback { -+ u32 buffer; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_feedback) == 16); -+ -+/** -+ * enum ipts_reset_type - Possible ways of resetting the device. -+ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. -+ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. -+ */ -+enum ipts_reset_type { -+ IPTS_RESET_TYPE_HARD = 0x00, -+ IPTS_RESET_TYPE_SOFT = 0x01, -+}; -+ -+/** -+ * struct ipts_reset - Payload for the RESET_SENSOR command. -+ * @type: How the device should get reset. -+ */ -+struct ipts_reset_sensor { -+ enum ipts_reset_type type; -+ u8 reserved[4]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_reset_sensor) == 8); -+ -+/** -+ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. -+ * @addr_lower: The lower 32 bits of the descriptor buffer address. -+ * @addr_upper: The upper 32 bits of the descriptor buffer address. -+ * @magic: A magic value. Must be 8. -+ */ -+struct ipts_get_descriptor { -+ u32 addr_lower; -+ u32 addr_upper; -+ u32 magic; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_get_descriptor) == 24); -+ -+/* -+ * The type of a response is indicated by a -+ * command code, with the most significant bit flipped to 1. -+ */ -+#define IPTS_RSP_BIT BIT(31) -+ -+/** -+ * struct ipts_response - Data returned from the device in response to a command. -+ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). -+ * @status: The return code of the command. -+ * @payload: The data that was produced by the command. -+ */ -+struct ipts_response { -+ enum ipts_command_code cmd; -+ enum ipts_status status; -+ u8 payload[80]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_response) == 88); -+ -+/** -+ * struct ipts_device_info - Vendor information of the IPTS device. -+ * @vendor: Vendor ID of this device. -+ * @product: Product ID of this device. -+ * @hw_version: Hardware revision of this device. -+ * @fw_version: Firmware revision of this device. -+ * @data_size: Requested size for a data buffer. -+ * @feedback_size: Requested size for a feedback buffer. -+ * @mode: Mode that the device currently operates in. -+ * @max_contacts: Maximum amount of concurrent touches the sensor can process. -+ * @sensor_min_eds: The minimum EDS version supported by the sensor. -+ * @sensor_max_eds: The maximum EDS version supported by the sensor. -+ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. -+ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. -+ * @intf_eds: The EDS version implemented by the interface between ME and host. -+ */ -+struct ipts_device_info { -+ u16 vendor; -+ u16 product; -+ u32 hw_version; -+ u32 fw_version; -+ u32 data_size; -+ u32 feedback_size; -+ enum ipts_mode mode; -+ u8 max_contacts; -+ u8 reserved1[3]; -+ u8 sensor_min_eds; -+ u8 sensor_maj_eds; -+ u8 me_min_eds; -+ u8 me_maj_eds; -+ u8 intf_eds; -+ u8 reserved2[11]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_device_info) == 44); -+ -+#endif /* IPTS_SPEC_DEVICE_H */ -diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h -new file mode 100644 -index 000000000000..5a58d4a0a610 ---- /dev/null -+++ b/drivers/hid/ipts/spec-hid.h -@@ -0,0 +1,34 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_HID_H -+#define IPTS_SPEC_HID_H -+ -+#include -+#include -+ -+/* -+ * Made-up type for passing raw IPTS data in a HID report. -+ */ -+#define IPTS_HID_FRAME_TYPE_RAW 0xEE -+ -+/** -+ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. -+ * @size: Size of the data inside the report, including this header. -+ * @type: What type of data does this report contain. -+ */ -+struct ipts_hid_header { -+ u32 size; -+ u8 reserved1; -+ u8 type; -+ u8 reserved2; -+ u8 data[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_hid_header) == 7); -+ -+#endif /* IPTS_SPEC_HID_H */ -diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c -new file mode 100644 -index 000000000000..355e92bea26f ---- /dev/null -+++ b/drivers/hid/ipts/thread.c -@@ -0,0 +1,84 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "thread.h" -+ -+bool ipts_thread_should_stop(struct ipts_thread *thread) -+{ -+ if (!thread) -+ return false; -+ -+ return READ_ONCE(thread->should_stop); -+} -+ -+static int ipts_thread_runner(void *data) -+{ -+ int ret = 0; -+ struct ipts_thread *thread = data; -+ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!thread->threadfn) -+ return -EFAULT; -+ -+ ret = thread->threadfn(thread); -+ complete_all(&thread->done); -+ -+ return ret; -+} -+ -+int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), -+ void *data, const char *name) -+{ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!threadfn) -+ return -EFAULT; -+ -+ init_completion(&thread->done); -+ -+ thread->data = data; -+ thread->should_stop = false; -+ thread->threadfn = threadfn; -+ -+ thread->thread = kthread_run(ipts_thread_runner, thread, name); -+ return PTR_ERR_OR_ZERO(thread->thread); -+} -+ -+int ipts_thread_stop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!thread->thread) -+ return 0; -+ -+ WRITE_ONCE(thread->should_stop, true); -+ -+ /* -+ * Make sure that the write has gone through before waiting. -+ */ -+ wmb(); -+ -+ wait_for_completion(&thread->done); -+ ret = kthread_stop(thread->thread); -+ -+ thread->thread = NULL; -+ thread->data = NULL; -+ thread->threadfn = NULL; -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h -new file mode 100644 -index 000000000000..1f966b8b32c4 ---- /dev/null -+++ b/drivers/hid/ipts/thread.h -@@ -0,0 +1,59 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_THREAD_H -+#define IPTS_THREAD_H -+ -+#include -+#include -+#include -+ -+/* -+ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible -+ * to issue MEI commands from that thread while it shuts itself down. By using a custom -+ * boolean variable and a completion object, we can call kthread_stop only when the thread -+ * already finished all of its work and has returned. -+ */ -+struct ipts_thread { -+ struct task_struct *thread; -+ -+ bool should_stop; -+ struct completion done; -+ -+ void *data; -+ int (*threadfn)(struct ipts_thread *thread); -+}; -+ -+/** -+ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. -+ * @thread: The current thread. -+ * -+ * Returns: true if the thread should stop, false if not. -+ */ -+bool ipts_thread_should_stop(struct ipts_thread *thread); -+ -+/** -+ * ipts_thread_start() - Starts an IPTS thread. -+ * @thread: The thread to initialize and start. -+ * @threadfn: The function to execute. -+ * @data: An argument that will be passed to threadfn. -+ * @name: The name of the new thread. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), -+ void *data, const char name[]); -+ -+/** -+ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. -+ * @thread: The thread that should stop. -+ * -+ * Returns: The return value of the thread function. -+ */ -+int ipts_thread_stop(struct ipts_thread *thread); -+ -+#endif /* IPTS_THREAD_H */ --- -2.47.1 - diff --git a/patches/6.14-rc4/0006-ithc.patch b/patches/6.14-rc4/0006-ithc.patch deleted file mode 100644 index 5d30b51b11..0000000000 --- a/patches/6.14-rc4/0006-ithc.patch +++ /dev/null @@ -1,2779 +0,0 @@ -From d07e07e448b9b1ac7102911263626b623f138a28 Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Sun, 11 Dec 2022 12:03:38 +0100 -Subject: [PATCH] iommu: intel: Disable source id verification for ITHC - -Signed-off-by: Dorian Stoll -Patchset: ithc ---- - drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 7a6d188e3bea..0179baee4596 100644 ---- a/drivers/iommu/intel/irq_remapping.c -+++ b/drivers/iommu/intel/irq_remapping.c -@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) - data.busmatch_count = 0; - pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); - -+ /* -+ * The Intel Touch Host Controller is at 00:10.6, but for some reason -+ * the MSI interrupts have request id 01:05.0. -+ * Disable id verification to work around this. -+ * FIXME Find proper fix or turn this into a quirk. -+ */ -+ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { -+ switch(dev->device) { -+ case 0x98d0: case 0x98d1: // LKF -+ case 0xa0d0: case 0xa0d1: // TGL LP -+ case 0x43d0: case 0x43d1: // TGL H -+ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); -+ return 0; -+ } -+ } -+ - /* - * DMA alias provides us with a PCI device and alias. The only case - * where the it will return an alias on a different bus than the --- -2.47.1 - -From 280c63dff160b59d1cbac71a63dc7f16d335fec9 Mon Sep 17 00:00:00 2001 -From: quo -Date: Sun, 11 Dec 2022 12:10:54 +0100 -Subject: [PATCH] hid: Add support for Intel Touch Host Controller - -Based on quo/ithc-linux@34539af4726d. - -Signed-off-by: Maximilian Stoll -Patchset: ithc ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 1 + - drivers/hid/ithc/Kbuild | 6 + - drivers/hid/ithc/Kconfig | 12 + - drivers/hid/ithc/ithc-debug.c | 149 ++++++++ - drivers/hid/ithc/ithc-debug.h | 7 + - drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ - drivers/hid/ithc/ithc-dma.h | 47 +++ - drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ - drivers/hid/ithc/ithc-hid.h | 32 ++ - drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ - drivers/hid/ithc/ithc-legacy.h | 8 + - drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.h | 39 ++ - drivers/hid/ithc/ithc-regs.c | 154 ++++++++ - drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ - drivers/hid/ithc/ithc.h | 89 +++++ - 18 files changed, 2568 insertions(+) - create mode 100644 drivers/hid/ithc/Kbuild - create mode 100644 drivers/hid/ithc/Kconfig - create mode 100644 drivers/hid/ithc/ithc-debug.c - create mode 100644 drivers/hid/ithc/ithc-debug.h - create mode 100644 drivers/hid/ithc/ithc-dma.c - create mode 100644 drivers/hid/ithc/ithc-dma.h - create mode 100644 drivers/hid/ithc/ithc-hid.c - create mode 100644 drivers/hid/ithc/ithc-hid.h - create mode 100644 drivers/hid/ithc/ithc-legacy.c - create mode 100644 drivers/hid/ithc/ithc-legacy.h - create mode 100644 drivers/hid/ithc/ithc-main.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.h - create mode 100644 drivers/hid/ithc/ithc-regs.c - create mode 100644 drivers/hid/ithc/ithc-regs.h - create mode 100644 drivers/hid/ithc/ithc.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 38eb29e4cc31..76ad7d9143c7 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1389,10 +1389,12 @@ source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/ipts/Kconfig" - -+source "drivers/hid/ithc/Kconfig" -+ - endif # HID - - # USB support may be used with HID disabled - - source "drivers/hid/usbhid/Kconfig" - - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 02588e5d01eb..1ea3d2e0d4e9 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -173,5 +173,6 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - - obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ - - obj-$(CONFIG_HID_IPTS) += ipts/ -+obj-$(CONFIG_HID_ITHC) += ithc/ -diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild -new file mode 100644 -index 000000000000..4937ba131297 ---- /dev/null -+++ b/drivers/hid/ithc/Kbuild -@@ -0,0 +1,6 @@ -+obj-$(CONFIG_HID_ITHC) := ithc.o -+ -+ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o -+ -+ccflags-y := -std=gnu11 -Wno-declaration-after-statement -+ -diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig -new file mode 100644 -index 000000000000..ede713023609 ---- /dev/null -+++ b/drivers/hid/ithc/Kconfig -@@ -0,0 +1,12 @@ -+config HID_ITHC -+ tristate "Intel Touch Host Controller" -+ depends on PCI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Touch Host Controller (ITHC / IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ithc. -diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c -new file mode 100644 -index 000000000000..2d8c6afe9966 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.c -@@ -0,0 +1,149 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+void ithc_log_regs(struct ithc *ithc) -+{ -+ if (!ithc->prev_regs) -+ return; -+ u32 __iomem *cur = (__iomem void *)ithc->regs; -+ u32 *prev = (void *)ithc->prev_regs; -+ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { -+ u32 x = readl(cur + i); -+ if (x != prev[i]) { -+ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); -+ prev[i] = x; -+ } -+ } -+} -+ -+static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, -+ loff_t *offset) -+{ -+ // Debug commands consist of a single letter followed by a list of numbers (decimal or -+ // hexadecimal, space-separated). -+ struct ithc *ithc = file_inode(f)->i_private; -+ char cmd[256]; -+ if (!ithc || !ithc->pci) -+ return -ENODEV; -+ if (!len) -+ return -EINVAL; -+ if (len >= sizeof(cmd)) -+ return -EINVAL; -+ if (copy_from_user(cmd, buf, len)) -+ return -EFAULT; -+ cmd[len] = 0; -+ if (cmd[len-1] == '\n') -+ cmd[len-1] = 0; -+ pci_info(ithc->pci, "debug command: %s\n", cmd); -+ -+ // Parse the list of arguments into a u32 array. -+ u32 n = 0; -+ const char *s = cmd + 1; -+ u32 a[32]; -+ while (*s && *s != '\n') { -+ if (n >= ARRAY_SIZE(a)) -+ return -EINVAL; -+ if (*s++ != ' ') -+ return -EINVAL; -+ char *e; -+ a[n++] = simple_strtoul(s, &e, 0); -+ if (e == s) -+ return -EINVAL; -+ s = e; -+ } -+ ithc_log_regs(ithc); -+ -+ // Execute the command. -+ switch (cmd[0]) { -+ case 'x': // reset -+ ithc_reset(ithc); -+ break; -+ case 'w': // write register: offset mask value -+ if (n != 3 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", -+ a[0], a[2], a[1]); -+ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); -+ break; -+ case 'r': // read register: offset -+ if (n != 1 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], -+ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); -+ break; -+ case 's': // spi command: cmd offset len data... -+ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ // set touch cfg: s 6 12 4 XX -+ if (n < 3 || a[2] > (n - 3) * 4) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); -+ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) -+ for (u32 i = 0; i < (a[2] + 3) / 4; i++) -+ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); -+ break; -+ case 'd': // dma command: cmd len data... -+ // get report descriptor: d 7 8 0 0 -+ // enable multitouch: d 3 2 0x0105 -+ if (n < 1) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); -+ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; -+ if (ithc_dma_tx(ithc, &data)) -+ pci_err(ithc->pci, "dma tx failed\n"); -+ break; -+ default: -+ return -EINVAL; -+ } -+ ithc_log_regs(ithc); -+ return len; -+} -+ -+static struct dentry *dbg_dir; -+ -+void __init ithc_debug_init_module(void) -+{ -+ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); -+ if (IS_ERR(d)) -+ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); -+ else -+ dbg_dir = d; -+} -+ -+void __exit ithc_debug_exit_module(void) -+{ -+ debugfs_remove_recursive(dbg_dir); -+ dbg_dir = NULL; -+} -+ -+static const struct file_operations ithc_debugfops_cmd = { -+ .owner = THIS_MODULE, -+ .write = ithc_debugfs_cmd_write, -+}; -+ -+static void ithc_debugfs_devres_release(struct device *dev, void *res) -+{ -+ struct dentry **dbgm = res; -+ debugfs_remove_recursive(*dbgm); -+} -+ -+int ithc_debug_init_device(struct ithc *ithc) -+{ -+ if (!dbg_dir) -+ return -ENOENT; -+ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); -+ if (!dbgm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, dbgm); -+ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); -+ if (IS_ERR(dbg)) -+ return PTR_ERR(dbg); -+ *dbgm = dbg; -+ -+ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); -+ if (IS_ERR(cmd)) -+ return PTR_ERR(cmd); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h -new file mode 100644 -index 000000000000..38c53d916bdb ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.h -@@ -0,0 +1,7 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+void ithc_debug_init_module(void); -+void ithc_debug_exit_module(void); -+int ithc_debug_init_device(struct ithc *ithc); -+void ithc_log_regs(struct ithc *ithc); -+ -diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c -new file mode 100644 -index 000000000000..bf4eab33062b ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.c -@@ -0,0 +1,312 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. -+// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. -+// This allows each data buffer to consist of multiple non-contiguous blocks of memory. -+ -+static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, -+ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) -+{ -+ p->num_pages = num_pages; -+ p->dir = dir; -+ // We allocate enough space to have one PRD per data buffer page, however if the data -+ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so -+ // some will remain unused (which is fine). -+ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); -+ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); -+ if (!p->addr) -+ return -ENOMEM; -+ if (p->dma_addr & (PAGE_SIZE - 1)) -+ return -EFAULT; -+ return 0; -+} -+ -+// Devres managed sg_table wrapper. -+struct ithc_sg_table { -+ void *addr; -+ struct sg_table sgt; -+ enum dma_data_direction dir; -+}; -+static void ithc_dma_sgtable_free(struct sg_table *sgt) -+{ -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_sg(sgt, sg, i) { -+ struct page *p = sg_page(sg); -+ if (p) -+ __free_page(p); -+ } -+ sg_free_table(sgt); -+} -+static void ithc_dma_data_devres_release(struct device *dev, void *res) -+{ -+ struct ithc_sg_table *sgt = res; -+ if (sgt->addr) -+ vunmap(sgt->addr); -+ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); -+ ithc_dma_sgtable_free(&sgt->sgt); -+} -+ -+static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b) -+{ -+ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be -+ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). -+ // We could use dma_alloc_noncontiguous(), however this still always allocates a single -+ // DMA mapped segment, which is more restrictive than what we need. -+ // Instead we use an sg_table of individually allocated pages. -+ struct page *pages[16]; -+ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) -+ return -EINVAL; -+ b->active_idx = -1; -+ struct ithc_sg_table *sgt = devres_alloc( -+ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); -+ if (!sgt) -+ return -ENOMEM; -+ sgt->dir = prds->dir; -+ -+ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { -+ struct scatterlist *sg; -+ int i; -+ bool ok = true; -+ for_each_sgtable_sg(&sgt->sgt, sg, i) { -+ // NOTE: don't need __GFP_DMA for PCI DMA -+ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); -+ if (!p) { -+ ok = false; -+ break; -+ } -+ sg_set_page(sg, p, PAGE_SIZE, 0); -+ } -+ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { -+ devres_add(&ithc->pci->dev, sgt); -+ b->sgt = &sgt->sgt; -+ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); -+ if (!b->addr) -+ return -ENOMEM; -+ return 0; -+ } -+ ithc_dma_sgtable_free(&sgt->sgt); -+ } -+ devres_free(sgt); -+ return -ENOMEM; -+} -+ -+static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Give a buffer to the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ if (b->active_idx >= 0) { -+ pci_err(ithc->pci, "buffer already active\n"); -+ return -EINVAL; -+ } -+ b->active_idx = idx; -+ if (prds->dir == DMA_TO_DEVICE) { -+ // TX buffer: Caller should have already filled the data buffer, so just fill -+ // the PRD and flush. -+ // (TODO: Support multi-page TX buffers. So far no device seems to use or need -+ // these though.) -+ if (b->data_size > PAGE_SIZE) -+ return -EINVAL; -+ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; -+ prd->size = b->data_size | PRD_FLAG_END; -+ flush_kernel_vmap_range(b->addr, b->data_size); -+ } else if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Reset PRDs. -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ prd->addr = sg_dma_address(sg) >> 10; -+ prd->size = sg_dma_len(sg); -+ prd++; -+ } -+ prd[-1].size |= PRD_FLAG_END; -+ } -+ dma_wmb(); // for the prds -+ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Take a buffer from the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ // This is purely a sanity check. We don't strictly need the idx parameter for this -+ // function, because it should always be the same as active_idx, unless we have a bug. -+ if (b->active_idx != idx) { -+ pci_err(ithc->pci, "wrong buffer index\n"); -+ return -EINVAL; -+ } -+ b->active_idx = -1; -+ if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Calculate actual received data size from PRDs. -+ dma_rmb(); // for the prds -+ b->data_size = 0; -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ unsigned int size = prd->size; -+ b->data_size += size & PRD_SIZE_MASK; -+ if (size & PRD_FLAG_END) -+ break; -+ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { -+ pci_err(ithc->pci, "truncated prd\n"); -+ break; -+ } -+ prd++; -+ } -+ invalidate_kernel_vmap_range(b->addr, b->data_size); -+ } -+ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_init(&rx->mutex); -+ -+ // Allocate buffers. -+ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", -+ NUM_RX_BUF, ithc->max_rx_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); -+ -+ // Init registers. -+ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); -+ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); -+ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); -+ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); -+ u8 head = readb(&ithc->regs->dma_rx[channel].head); -+ if (head) { -+ pci_err(ithc->pci, "head is nonzero (%u)\n", head); -+ return -EIO; -+ } -+ -+ // Init buffers. -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); -+ -+ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); -+ return 0; -+} -+ -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) -+{ -+ bitsb_set(&ithc->regs->dma_rx[channel].control, -+ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, -+ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); -+} -+ -+int ithc_dma_tx_init(struct ithc *ithc) -+{ -+ struct ithc_dma_tx *tx = &ithc->dma_tx; -+ mutex_init(&tx->mutex); -+ -+ // Allocate buffers. -+ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", -+ ithc->max_tx_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); -+ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); -+ -+ // Init registers. -+ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); -+ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); -+ -+ // Init buffers. -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ return 0; -+} -+ -+static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) -+{ -+ // Process all filled RX buffers from the ringbuffer. -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ unsigned int n = rx->num_received; -+ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); -+ while (1) { -+ u8 tail = n % NUM_RX_BUF; -+ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); -+ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); -+ // ringbuffer is full if tail_wrap == head_wrap -+ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG -+ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) -+ return 0; -+ -+ // take the buffer that the device just filled -+ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); -+ rx->num_received = ++n; -+ -+ // process data -+ struct ithc_data d; -+ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) -+ (ithc, b->addr, b->data_size, &d) < 0) { -+ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", -+ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); -+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -+ b->addr, min(b->data_size, 0x400u), 0); -+ } else { -+ ithc_hid_process_data(ithc, &d); -+ } -+ -+ // give the buffer back to the device -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); -+ } -+} -+int ithc_dma_rx(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_lock(&rx->mutex); -+ int ret = ithc_dma_rx_unlocked(ithc, channel); -+ mutex_unlock(&rx->mutex); -+ return ret; -+} -+ -+static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) -+{ -+ // Send a single TX buffer to the THC. -+ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ -+ // Fill the TX buffer with header and data. -+ ssize_t sz; -+ if (data->type == ITHC_DATA_RAW) { -+ sz = min(data->size, ithc->max_tx_size); -+ memcpy(ithc->dma_tx.buf.addr, data->data, sz); -+ } else { -+ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) -+ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); -+ } -+ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ if (sz < 0) { -+ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", -+ data->type, data->size, (int)sz); -+ return -EINVAL; -+ } -+ -+ // Let the THC process the buffer. -+ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); -+ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); -+ return 0; -+} -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) -+{ -+ mutex_lock(&ithc->dma_tx.mutex); -+ int ret = ithc_dma_tx_unlocked(ithc, data); -+ mutex_unlock(&ithc->dma_tx.mutex); -+ return ret; -+} -+ -diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h -new file mode 100644 -index 000000000000..1749a5819b3e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define PRD_SIZE_MASK 0xffffff -+#define PRD_FLAG_END 0x1000000 -+#define PRD_FLAG_SUCCESS 0x2000000 -+#define PRD_FLAG_ERROR 0x4000000 -+ -+struct ithc_phys_region_desc { -+ u64 addr; // physical addr/1024 -+ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds -+ u32 unused; -+}; -+ -+struct ithc_dma_prd_buffer { -+ void *addr; -+ dma_addr_t dma_addr; -+ u32 size; -+ u32 num_pages; // per data buffer -+ enum dma_data_direction dir; -+}; -+ -+struct ithc_dma_data_buffer { -+ void *addr; -+ struct sg_table *sgt; -+ int active_idx; -+ u32 data_size; -+}; -+ -+struct ithc_dma_tx { -+ struct mutex mutex; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer buf; -+}; -+ -+struct ithc_dma_rx { -+ struct mutex mutex; -+ u32 num_received; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; -+}; -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel); -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); -+int ithc_dma_tx_init(struct ithc *ithc); -+int ithc_dma_rx(struct ithc *ithc, u8 channel); -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); -+ -diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c -new file mode 100644 -index 000000000000..065646ab499e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.c -@@ -0,0 +1,207 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+static int ithc_hid_start(struct hid_device *hdev) { return 0; } -+static void ithc_hid_stop(struct hid_device *hdev) { } -+static int ithc_hid_open(struct hid_device *hdev) { return 0; } -+static void ithc_hid_close(struct hid_device *hdev) { } -+ -+static int ithc_hid_parse(struct hid_device *hdev) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; -+ WRITE_ONCE(ithc->hid.parse_done, false); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); -+ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), -+ msecs_to_jiffies(200))) { -+ ithc_log_regs(ithc); -+ return 0; -+ } -+ if (retries > 5) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "failed to read report descriptor\n"); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -+ } -+} -+ -+static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -+ size_t len, unsigned char rtype, int reqtype) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ if (!buf || !len) -+ return -EINVAL; -+ -+ struct ithc_data d = { .size = len, .data = buf }; -+ buf[0] = reportnum; -+ -+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_OUTPUT_REPORT; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_SET_FEATURE; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -+ d.type = ITHC_DATA_GET_FEATURE; -+ d.data = &reportnum; -+ d.size = 1; -+ -+ // Prepare for response. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = buf; -+ ithc->hid.get_feature_size = len; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ -+ // Transmit 'get feature' request. -+ int r = CHECK(ithc_dma_tx, ithc, &d); -+ if (!r) { -+ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, -+ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); -+ if (!r) -+ r = -ETIMEDOUT; -+ else if (r < 0) -+ r = -EINTR; -+ else -+ r = 0; -+ } -+ -+ // If everything went ok, the buffer has been filled with the response data. -+ // Return the response size. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = NULL; -+ if (!r) -+ r = ithc->hid.get_feature_size; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ return r; -+ } -+ -+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -+ rtype, reqtype, reportnum); -+ return -EINVAL; -+} -+ -+// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to -+// cast away the const to avoid a compiler warning... -+#define NOCONST(x) ((void *)x) -+ -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) -+{ -+ WARN_ON(!ithc->hid.dev); -+ if (!ithc->hid.dev) -+ return; -+ -+ switch (d->type) { -+ -+ case ITHC_DATA_IGNORE: -+ return; -+ -+ case ITHC_DATA_ERROR: -+ CHECK(ithc_reset, ithc); -+ return; -+ -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ // Response to the report descriptor request sent by ithc_hid_parse(). -+ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); -+ WRITE_ONCE(ithc->hid.parse_done, true); -+ wake_up(&ithc->hid.wait_parse); -+ return; -+ -+ case ITHC_DATA_INPUT_REPORT: -+ { -+ // Standard HID input report. -+ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); -+ if (r < 0) { -+ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", -+ r, d->size, d->size ? *(u8 *)d->data : 0); -+ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, -+ d->data, min(d->size, 0x400u), 0); -+ } -+ return; -+ } -+ -+ case ITHC_DATA_GET_FEATURE: -+ { -+ // Response to a 'get feature' request sent by ithc_hid_raw_request(). -+ bool done = false; -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ if (ithc->hid.get_feature_buf) { -+ if (d->size < ithc->hid.get_feature_size) -+ ithc->hid.get_feature_size = d->size; -+ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); -+ ithc->hid.get_feature_buf = NULL; -+ done = true; -+ } -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ if (done) { -+ wake_up(&ithc->hid.wait_get_feature); -+ } else { -+ // Received data without a matching request, or the request already -+ // timed out. (XXX What's the correct thing to do here?) -+ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, -+ NOCONST(d->data), d->size, 1); -+ } -+ return; -+ } -+ -+ default: -+ pci_err(ithc->pci, "unhandled data type %i\n", d->type); -+ return; -+ } -+} -+ -+static struct hid_ll_driver ithc_ll_driver = { -+ .start = ithc_hid_start, -+ .stop = ithc_hid_stop, -+ .open = ithc_hid_open, -+ .close = ithc_hid_close, -+ .parse = ithc_hid_parse, -+ .raw_request = ithc_hid_raw_request, -+}; -+ -+static void ithc_hid_devres_release(struct device *dev, void *res) -+{ -+ struct hid_device **hidm = res; -+ if (*hidm) -+ hid_destroy_device(*hidm); -+} -+ -+int ithc_hid_init(struct ithc *ithc) -+{ -+ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -+ if (!hidm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, hidm); -+ struct hid_device *hid = hid_allocate_device(); -+ if (IS_ERR(hid)) -+ return PTR_ERR(hid); -+ *hidm = hid; -+ -+ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -+ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -+ hid->ll_driver = &ithc_ll_driver; -+ hid->bus = BUS_PCI; -+ hid->vendor = ithc->vendor_id; -+ hid->product = ithc->product_id; -+ hid->version = 0x100; -+ hid->dev.parent = &ithc->pci->dev; -+ hid->driver_data = ithc; -+ -+ ithc->hid.dev = hid; -+ -+ init_waitqueue_head(&ithc->hid.wait_parse); -+ init_waitqueue_head(&ithc->hid.wait_get_feature); -+ mutex_init(&ithc->hid.get_feature_mutex); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h -new file mode 100644 -index 000000000000..599eb912c8c8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+enum ithc_data_type { -+ ITHC_DATA_IGNORE, -+ ITHC_DATA_RAW, -+ ITHC_DATA_ERROR, -+ ITHC_DATA_REPORT_DESCRIPTOR, -+ ITHC_DATA_INPUT_REPORT, -+ ITHC_DATA_OUTPUT_REPORT, -+ ITHC_DATA_GET_FEATURE, -+ ITHC_DATA_SET_FEATURE, -+}; -+ -+struct ithc_data { -+ enum ithc_data_type type; -+ u32 size; -+ const void *data; -+}; -+ -+struct ithc_hid { -+ struct hid_device *dev; -+ bool parse_done; -+ wait_queue_head_t wait_parse; -+ wait_queue_head_t wait_get_feature; -+ struct mutex get_feature_mutex; -+ void *get_feature_buf; -+ size_t get_feature_size; -+}; -+ -+int ithc_hid_init(struct ithc *ithc); -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); -+ -diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c -new file mode 100644 -index 000000000000..8883987fb352 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.c -@@ -0,0 +1,254 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) -+#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) -+ -+#define DEVCFG_TOUCH_MASK 0x3f -+#define DEVCFG_TOUCH_ENABLE BIT(0) -+#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) -+#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) -+#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) -+#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) -+ -+#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" -+ -+#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) -+#define DEVCFG_SPI_CLKDIV_8 BIT(4) -+#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) -+#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) -+#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) -+#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) -+#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) -+#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat -+#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) -+#define DEVCFG_SPI_UNKNOWN_25 BIT(25) -+#define DEVCFG_SPI_UNKNOWN_26 BIT(26) -+#define DEVCFG_SPI_UNKNOWN_27 BIT(27) -+#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this -+#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? -+ -+struct ithc_device_config { // (Example values are from an SP7+.) -+ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) -+ u32 error; // 04 = 0x00000000 -+ u32 dma_buf_sizes; // 08 = 0x000a00ff -+ u32 touch_cfg; // 0c = 0x0000001c -+ u32 touch_state; // 10 = 0x0000001c -+ u32 device_id; // 14 = 0x43495424 = "$TIC" -+ u32 spi_config; // 18 = 0xfda00a2e -+ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. -+ u16 product_id; // 1e = 0x0c1a -+ u32 revision; // 20 = 0x00000001 -+ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) -+ u32 command; // 28 = 0x00000000 -+ u32 fw_mode; // 2c = 0x00000000 (for fw update?) -+ u32 _unknown_30; // 30 = 0x00000000 -+ u8 eds_minor_ver; // 34 = 0x5e -+ u8 eds_major_ver; // 35 = 0x03 -+ u8 interface_rev; // 36 = 0x04 -+ u8 eu_kernel_ver; // 37 = 0x04 -+ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) -+ u32 _unknown_3c; // 3c = 0x00000002 -+}; -+static_assert(sizeof(struct ithc_device_config) == 64); -+ -+#define RX_CODE_INPUT_REPORT 3 -+#define RX_CODE_FEATURE_REPORT 4 -+#define RX_CODE_REPORT_DESCRIPTOR 5 -+#define RX_CODE_RESET 7 -+ -+#define TX_CODE_SET_FEATURE 3 -+#define TX_CODE_GET_FEATURE 4 -+#define TX_CODE_OUTPUT_REPORT 5 -+#define TX_CODE_GET_REPORT_DESCRIPTOR 7 -+ -+static int ithc_set_device_enabled(struct ithc *ithc, bool enable) -+{ -+ u32 x = ithc->legacy_touch_cfg = -+ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | -+ DEVCFG_TOUCH_HID_REPORT_ENABLE | -+ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); -+ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -+ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); -+} -+ -+int ithc_legacy_init(struct ithc *ithc) -+{ -+ // Since we don't yet know which SPI config the device wants, use default speed and mode -+ // initially for reading config data. -+ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); -+ -+ // Setting the following bit seems to make reading the config more reliable. -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ // Setting this bit may be necessary on ADL devices. -+ switch (ithc->pci->device) { -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); -+ break; -+ } -+ -+ // Take the touch device out of reset. -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -+ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) -+ break; -+ if (retries > 5) { -+ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", -+ readl(&ithc->regs->irq_cause)); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ if (msleep_interruptible(1000)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ -+ // Read configuration data. -+ u32 spi_cfg; -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ struct ithc_device_config config = { 0 }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); -+ u32 *p = (void *)&config; -+ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { -+ spi_cfg = config.spi_config; -+ ithc->vendor_id = config.vendor_id; -+ ithc->product_id = config.product_id; -+ ithc->product_rev = config.revision; -+ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); -+ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); -+ ithc->legacy_touch_cfg = config.touch_cfg; -+ ithc->have_config = true; -+ break; -+ } -+ if (retries > 10) { -+ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -+ config.device_id); -+ return -EIO; -+ } -+ pci_warn(ithc->pci, "failed to read config, retrying\n"); -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ // Apply SPI config and enable touch device. -+ CHECK_RET(ithc_set_spi_config, ithc, -+ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, -+ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : -+ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : -+ SPI_MODE_SINGLE, -+ SPI_MODE_SINGLE); -+ CHECK_RET(ithc_set_device_enabled, ithc, true); -+ ithc_log_regs(ithc); -+ return 0; -+} -+ -+void ithc_legacy_exit(struct ithc *ithc) -+{ -+ CHECK(ithc_set_device_enabled, ithc, false); -+} -+ -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct { -+ u32 code; -+ u32 data_size; -+ u32 _unknown[14]; -+ } *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // Note: RX data is not padded, even though TX data must be padded. -+ if (len != sizeof(*hdr) + hdr->data_size) -+ return -EMSGSIZE; -+ -+ dest->data = hdr + 1; -+ dest->size = hdr->data_size; -+ -+ switch (hdr->code) { -+ case RX_CODE_RESET: -+ // The THC sends a reset request when we need to reinitialize the device. -+ // This usually only happens if we send an invalid command or put the device -+ // in a bad state. -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case RX_CODE_REPORT_DESCRIPTOR: -+ // The descriptor is preceded by 8 nul bytes. -+ if (hdr->data_size < 8) -+ return -ENODATA; -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = (char *)(hdr + 1) + 8; -+ dest->size = hdr->data_size - 8; -+ return 0; -+ case RX_CODE_INPUT_REPORT: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ return 0; -+ case RX_CODE_FEATURE_REPORT: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct { -+ u32 code; -+ u32 data_size; -+ } *hdr = dest; -+ -+ size_t src_size = src->size; -+ const void *src_data = src->data; -+ const u64 get_report_desc_data = 0; -+ u32 code; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ code = TX_CODE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ code = TX_CODE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ code = TX_CODE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ code = TX_CODE_GET_REPORT_DESCRIPTOR; -+ src_size = sizeof(get_report_desc_data); -+ src_data = &get_report_desc_data; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->code = code; -+ hdr->data_size = src_size; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h -new file mode 100644 -index 000000000000..28d692462072 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.h -@@ -0,0 +1,8 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+int ithc_legacy_init(struct ithc *ithc); -+void ithc_legacy_exit(struct ithc *ithc); -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -new file mode 100644 -index 000000000000..ac56c253674b ---- /dev/null -+++ b/drivers/hid/ithc/ithc-main.c -@@ -0,0 +1,431 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+MODULE_DESCRIPTION("Intel Touch Host Controller driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+ -+static const struct pci_device_id ithc_pci_tbl[] = { -+ { -+ .vendor = PCI_VENDOR_ID_INTEL, -+ .device = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subdevice = PCI_ANY_ID, -+ .class = PCI_CLASS_INPUT_PEN << 8, -+ .class_mask = ~0, -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); -+ -+// Module parameters -+ -+static bool ithc_use_polling = false; -+module_param_named(poll, ithc_use_polling, bool, 0); -+MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); -+ -+// Since all known devices seem to use only channel 1, by default we disable channel 0. -+static bool ithc_use_rx0 = false; -+module_param_named(rx0, ithc_use_rx0, bool, 0); -+MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); -+ -+static bool ithc_use_rx1 = true; -+module_param_named(rx1, ithc_use_rx1, bool, 0); -+MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); -+ -+static int ithc_active_ltr_us = -1; -+module_param_named(activeltr, ithc_active_ltr_us, int, 0); -+MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); -+ -+static int ithc_idle_ltr_us = -1; -+module_param_named(idleltr, ithc_idle_ltr_us, int, 0); -+MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); -+ -+static unsigned int ithc_idle_delay_ms = 1000; -+module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); -+MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); -+ -+static bool ithc_log_regs_enabled = false; -+module_param_named(logregs, ithc_log_regs_enabled, bool, 0); -+MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); -+ -+// Interrupts/polling -+ -+static void ithc_disable_interrupts(struct ithc *ithc) -+{ -+ writel(0, &ithc->regs->error_control); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); -+} -+ -+static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) -+{ -+ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, -+ &ithc->regs->dma_rx[channel].status); -+} -+ -+static void ithc_clear_interrupts(struct ithc *ithc) -+{ -+ writel(0xffffffff, &ithc->regs->error_flags); -+ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, -+ &ithc->regs->dma_tx.status); -+} -+ -+static void ithc_idle_timer_callback(struct timer_list *t) -+{ -+ struct ithc *ithc = container_of(t, struct ithc, idle_timer); -+ ithc_set_ltr_idle(ithc); -+} -+ -+static void ithc_process(struct ithc *ithc) -+{ -+ ithc_log_regs(ithc); -+ -+ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. -+ // It does not appear to automatically go back to idle, so we switch it back after a delay. -+ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); -+ -+ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ -+ // Read and clear error bits -+ u32 err = readl(&ithc->regs->error_flags); -+ if (err) { -+ writel(err, &ithc->regs->error_flags); -+ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "error flags: 0x%08x\n", err); -+ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); -+ } -+ -+ // Process DMA rx -+ if (ithc_use_rx0) { -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ if (rx0) -+ ithc_dma_rx(ithc, 0); -+ } -+ if (ithc_use_rx1) { -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ if (rx1) -+ ithc_dma_rx(ithc, 1); -+ } -+ -+ ithc_log_regs(ithc); -+} -+ -+static irqreturn_t ithc_interrupt_thread(int irq, void *arg) -+{ -+ struct ithc *ithc = arg; -+ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", -+ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), -+ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), -+ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), -+ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), -+ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); -+ ithc_process(ithc); -+ return IRQ_HANDLED; -+} -+ -+static int ithc_poll_thread(void *arg) -+{ -+ struct ithc *ithc = arg; -+ unsigned int sleep = 100; -+ while (!kthread_should_stop()) { -+ u32 n = ithc->dma_rx[1].num_received; -+ ithc_process(ithc); -+ // Decrease polling interval to 20ms if we received data, otherwise slowly -+ // increase it up to 200ms. -+ sleep = n != ithc->dma_rx[1].num_received ? 20 -+ : min(200u, sleep + (sleep >> 4) + 1); -+ msleep_interruptible(sleep); -+ } -+ return 0; -+} -+ -+// Device initialization and shutdown -+ -+static void ithc_disable(struct ithc *ithc) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); -+ ithc_disable_interrupts(ithc); -+ ithc_clear_interrupts(ithc); -+} -+ -+static int ithc_init_device(struct ithc *ithc) -+{ -+ // Read ACPI config for QuickSPI mode -+ struct ithc_acpi_config cfg = { 0 }; -+ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); -+ if (!cfg.has_config) -+ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); -+ else -+ ithc_print_acpi_config(ithc, &cfg); -+ ithc->use_quickspi = cfg.has_config; -+ -+ // Shut down device -+ ithc_log_regs(ithc); -+ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; -+ ithc_disable(ithc); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); -+ ithc_log_regs(ithc); -+ -+ // If the device was previously enabled, wait a bit to make sure it's fully shut down. -+ if (was_enabled) -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ -+ // Set Latency Tolerance Reporting config. The device will automatically -+ // apply these values depending on whether it is active or idle. -+ // If active value is too high, DMA buffer data can become truncated. -+ // By default, we set the active LTR value to 50us, and idle to 100ms. -+ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 -+ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 -+ : 50 * 1000; -+ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 -+ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 -+ : 100 * 1000 * 1000; -+ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); -+ -+ if (ithc->use_quickspi) -+ CHECK_RET(ithc_quickspi_init, ithc, &cfg); -+ else -+ CHECK_RET(ithc_legacy_init, ithc); -+ -+ return 0; -+} -+ -+int ithc_reset(struct ithc *ithc) -+{ -+ // FIXME This should probably do devres_release_group()+ithc_start(). -+ // But because this is called during DMA processing, that would have to be done -+ // asynchronously (schedule_work()?). And with extra locking? -+ pci_err(ithc->pci, "reset\n"); -+ CHECK(ithc_init_device, ithc); -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "reset completed\n"); -+ return 0; -+} -+ -+static void ithc_stop(void *res) -+{ -+ struct ithc *ithc = res; -+ pci_dbg(ithc->pci, "stopping\n"); -+ ithc_log_regs(ithc); -+ -+ if (ithc->poll_thread) -+ CHECK(kthread_stop, ithc->poll_thread); -+ if (ithc->irq >= 0) -+ disable_irq(ithc->irq); -+ if (ithc->use_quickspi) -+ ithc_quickspi_exit(ithc); -+ else -+ ithc_legacy_exit(ithc); -+ ithc_disable(ithc); -+ del_timer_sync(&ithc->idle_timer); -+ -+ // Clear DMA config. -+ for (unsigned int i = 0; i < 2; i++) { -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); -+ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); -+ writeb(0, &ithc->regs->dma_rx[i].num_bufs); -+ writeb(0, &ithc->regs->dma_rx[i].num_prds); -+ } -+ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); -+ writeb(0, &ithc->regs->dma_tx.num_prds); -+ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "stopped\n"); -+} -+ -+static void ithc_clear_drvdata(void *res) -+{ -+ struct pci_dev *pci = res; -+ pci_set_drvdata(pci, NULL); -+} -+ -+static int ithc_start(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "starting\n"); -+ if (pci_get_drvdata(pci)) { -+ pci_err(pci, "device already initialized\n"); -+ return -EINVAL; -+ } -+ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) -+ return -ENOMEM; -+ -+ // Allocate/init main driver struct. -+ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); -+ if (!ithc) -+ return -ENOMEM; -+ ithc->irq = -1; -+ ithc->pci = pci; -+ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); -+ pci_set_drvdata(pci, ithc); -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); -+ if (ithc_log_regs_enabled) -+ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); -+ -+ // PCI initialization. -+ CHECK_RET(pcim_enable_device, pci); -+ pci_set_master(pci); -+ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); -+ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); -+ CHECK_RET(pci_set_power_state, pci, PCI_D0); -+ ithc->regs = pcim_iomap_table(pci)[0]; -+ -+ // Allocate IRQ. -+ if (!ithc_use_polling) { -+ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); -+ ithc->irq = CHECK(pci_irq_vector, pci, 0); -+ if (ithc->irq < 0) -+ return ithc->irq; -+ } -+ -+ // Initialize THC and touch device. -+ CHECK_RET(ithc_init_device, ithc); -+ -+ // Initialize HID and DMA. -+ CHECK_RET(ithc_hid_init, ithc); -+ if (ithc_use_rx0) -+ CHECK_RET(ithc_dma_rx_init, ithc, 0); -+ if (ithc_use_rx1) -+ CHECK_RET(ithc_dma_rx_init, ithc, 1); -+ CHECK_RET(ithc_dma_tx_init, ithc); -+ -+ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); -+ -+ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are -+ // disabled BEFORE the buffers are freed. -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); -+ -+ // Start polling/IRQ. -+ if (ithc_use_polling) { -+ pci_info(pci, "using polling instead of irq\n"); -+ // Use a thread instead of simple timer because we want to be able to sleep. -+ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); -+ if (IS_ERR(ithc->poll_thread)) { -+ int err = PTR_ERR(ithc->poll_thread); -+ ithc->poll_thread = NULL; -+ return err; -+ } -+ } else { -+ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, -+ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); -+ } -+ -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ -+ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, -+ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. -+ CHECK_RET(hid_add_device, ithc->hid.dev); -+ -+ CHECK(ithc_debug_init_device, ithc); -+ -+ ithc_set_ltr_idle(ithc); -+ -+ pci_dbg(pci, "started\n"); -+ return 0; -+} -+ -+static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) -+{ -+ pci_dbg(pci, "device probe\n"); -+ return ithc_start(pci); -+} -+ -+static void ithc_remove(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "device remove\n"); -+ // all cleanup is handled by devres -+} -+ -+// For suspend/resume, we just deinitialize and reinitialize everything. -+// TODO It might be cleaner to keep the HID device around, however we would then have to signal -+// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set -+// feature' requests. Hidraw does not seem to have a facility to do that. -+static int ithc_suspend(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm suspend\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_resume(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm resume\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_freeze(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm freeze\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_thaw(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm thaw\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_restore(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm restore\n"); -+ return ithc_start(pci); -+} -+ -+static struct pci_driver ithc_driver = { -+ .name = DEVNAME, -+ .id_table = ithc_pci_tbl, -+ .probe = ithc_probe, -+ .remove = ithc_remove, -+ .driver.pm = &(const struct dev_pm_ops) { -+ .suspend = ithc_suspend, -+ .resume = ithc_resume, -+ .freeze = ithc_freeze, -+ .thaw = ithc_thaw, -+ .restore = ithc_restore, -+ }, -+ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, -+}; -+ -+static int __init ithc_init(void) -+{ -+ ithc_debug_init_module(); -+ return pci_register_driver(&ithc_driver); -+} -+ -+static void __exit ithc_exit(void) -+{ -+ pci_unregister_driver(&ithc_driver); -+ ithc_debug_exit_module(); -+} -+ -+module_init(ithc_init); -+module_exit(ithc_exit); -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c -new file mode 100644 -index 000000000000..e2d1690b8cf8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.c -@@ -0,0 +1,607 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+// Some public THC/QuickSPI documentation can be found in: -+// - Intel Firmware Support Package repo: https://github.com/intel/FSP -+// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 -+ -+#include "ithc.h" -+ -+static const guid_t guid_hidspi = -+ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); -+static const guid_t guid_thc_quickspi = -+ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); -+static const guid_t guid_thc_ltr = -+ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); -+ -+// TODO The HIDSPI spec says revision should be 3. Should we try both? -+#define DSM_REV 2 -+ -+struct hidspi_header { -+ u8 type; -+ u16 len; -+ u8 id; -+} __packed; -+static_assert(sizeof(struct hidspi_header) == 4); -+ -+#define HIDSPI_INPUT_TYPE_DATA 1 -+#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 -+#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 -+#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 -+#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 -+#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 -+#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 -+#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 -+#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 -+ -+#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 -+#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 -+#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 -+#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 -+#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 -+#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 -+#define HIDSPI_OUTPUT_TYPE_COMMAND 7 -+ -+struct hidspi_device_descriptor { -+ u16 wDeviceDescLength; -+ u16 bcdVersion; -+ u16 wReportDescLength; -+ u16 wMaxInputLength; -+ u16 wMaxOutputLength; -+ u16 wMaxFragmentLength; -+ u16 wVendorID; -+ u16 wProductID; -+ u16 wVersionID; -+ u16 wFlags; -+ u32 dwReserved; -+}; -+static_assert(sizeof(struct hidspi_device_descriptor) == 24); -+ -+static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_INTEGER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); -+ *dest = (u32)o->integer.value; -+ ACPI_FREE(o); -+ return 1; -+} -+ -+static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_BUFFER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ if (o->buffer.length != len) { -+ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", -+ guid, func, o->buffer.length, len); -+ ACPI_FREE(o); -+ return -1; -+ } -+ memcpy(dest, o->buffer.pointer, len); -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); -+ ACPI_FREE(o); -+ return 1; -+} -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) -+{ -+ int r; -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ -+ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); -+ if (!cfg->has_config) -+ return 0; -+ -+ // HIDSPI settings -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_header_address = r > 0; -+ if (r > 0 && cfg->input_report_header_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", -+ cfg->input_report_header_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_body_address = r > 0; -+ if (r > 0 && cfg->input_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", -+ cfg->input_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_output_report_body_address = r > 0; -+ if (r > 0 && cfg->output_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", -+ cfg->output_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_read_opcode = r > 0; -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_write_opcode = r > 0; -+ -+ u32 flags; -+ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); -+ if (r < 0) -+ return r; -+ cfg->has_read_mode = cfg->has_write_mode = r > 0; -+ if (r > 0) { -+ cfg->read_mode = (flags >> 14) & 3; -+ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; -+ } -+ -+ // Quick SPI settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); -+ if (r < 0) -+ return r; -+ cfg->has_spi_frequency = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); -+ if (r < 0) -+ return r; -+ cfg->has_limit_packet_size = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); -+ if (r < 0) -+ return r; -+ cfg->has_tx_delay = r > 0; -+ if (r > 0) -+ cfg->tx_delay &= 0xffff; -+ -+ // LTR settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_active_ltr = r > 0; -+ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { -+ if (cfg->active_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", -+ cfg->active_ltr); -+ cfg->active_ltr = 500; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_idle_ltr = r > 0; -+ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { -+ if (cfg->idle_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", -+ cfg->idle_ltr); -+ cfg->idle_ltr = 500; -+ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) -+ cfg->idle_ltr = cfg->active_ltr; -+ } -+ -+ return 0; -+} -+ -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ if (!cfg->has_config) { -+ pci_info(ithc->pci, "No ACPI config"); -+ return; -+ } -+ -+ char input_report_header_address[16] = "-"; -+ if (cfg->has_input_report_header_address) -+ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); -+ char input_report_body_address[16] = "-"; -+ if (cfg->has_input_report_body_address) -+ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); -+ char output_report_body_address[16] = "-"; -+ if (cfg->has_output_report_body_address) -+ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); -+ char read_opcode[16] = "-"; -+ if (cfg->has_read_opcode) -+ sprintf(read_opcode, "0x%02x", cfg->read_opcode); -+ char write_opcode[16] = "-"; -+ if (cfg->has_write_opcode) -+ sprintf(write_opcode, "0x%02x", cfg->write_opcode); -+ char read_mode[16] = "-"; -+ if (cfg->has_read_mode) -+ sprintf(read_mode, "%i", cfg->read_mode); -+ char write_mode[16] = "-"; -+ if (cfg->has_write_mode) -+ sprintf(write_mode, "%i", cfg->write_mode); -+ char spi_frequency[16] = "-"; -+ if (cfg->has_spi_frequency) -+ sprintf(spi_frequency, "%u", cfg->spi_frequency); -+ char limit_packet_size[16] = "-"; -+ if (cfg->has_limit_packet_size) -+ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); -+ char tx_delay[16] = "-"; -+ if (cfg->has_tx_delay) -+ sprintf(tx_delay, "%u", cfg->tx_delay); -+ char active_ltr[16] = "-"; -+ if (cfg->has_active_ltr) -+ sprintf(active_ltr, "%u", cfg->active_ltr); -+ char idle_ltr[16] = "-"; -+ if (cfg->has_idle_ltr) -+ sprintf(idle_ltr, "%u", cfg->idle_ltr); -+ -+ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", -+ input_report_header_address, input_report_body_address, output_report_body_address, -+ read_opcode, write_opcode, read_mode, write_mode, -+ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); -+} -+ -+static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) -+{ -+ writeb(opcode, &ithc->regs->opcode[i].header); -+ writeb(opcode, &ithc->regs->opcode[i].single); -+ writeb(opcode, &ithc->regs->opcode[i].dual); -+ writeb(opcode, &ithc->regs->opcode[i].quad); -+} -+ -+static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); -+ -+ // SPI frequency and mode -+ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { -+ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); -+ return -EINVAL; -+ } -+ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); -+ bool clkdiv8 = clkdiv > 7; -+ if (clkdiv8) -+ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); -+ if (!clkdiv) -+ clkdiv = 1; -+ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, -+ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, -+ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); -+ -+ // SPI addresses and opcodes -+ if (cfg->has_input_report_header_address) -+ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); -+ if (cfg->has_input_report_body_address) { -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); -+ } -+ if (cfg->has_output_report_body_address) -+ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); -+ -+ switch (ithc->pci->device) { -+ // LKF/TGL don't support QuickSPI. -+ // For ADL, opcode layout is RX/TX/unused. -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ if (cfg->has_read_opcode) { -+ set_opcode(ithc, 0, cfg->read_opcode); -+ } -+ if (cfg->has_write_opcode) { -+ set_opcode(ithc, 1, cfg->write_opcode); -+ } -+ break; -+ // For MTL, opcode layout was changed to RX/RX/TX. -+ // (RPL layout is unknown.) -+ default: -+ if (cfg->has_read_opcode) { -+ set_opcode(ithc, 0, cfg->read_opcode); -+ set_opcode(ithc, 1, cfg->read_opcode); -+ } -+ if (cfg->has_write_opcode) { -+ set_opcode(ithc, 2, cfg->write_opcode); -+ } -+ break; -+ } -+ -+ ithc_log_regs(ithc); -+ -+ // The rest... -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), -+ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); -+ -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), -+ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(2)); -+ -+ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), -+ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); -+ -+ bitsl_set(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); -+ -+ return 0; -+} -+ -+static int wait_for_report(struct ithc *ithc) -+{ -+ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, -+ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); -+ -+ u32 h = readl(&ithc->regs->input_header); -+ ithc_log_regs(ithc); -+ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE -+ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { -+ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); -+ return -ENODATA; -+ } -+ return INPUT_HEADER_REPORT_LENGTH(h) * 4; -+} -+ -+static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing HIDSPI\n"); -+ -+ // HIDSPI initialization sequence: -+ // "1. The host shall invoke the ACPI reset method to clear the device state." -+ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); -+ if (ACPI_FAILURE(s)) { -+ pci_err(ithc->pci, "ACPI reset failed\n"); -+ return -EIO; -+ } -+ -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ -+ // "2. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing a device reset response." -+ int size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(struct hidspi_header)) { -+ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "3. The host shall read the reset response from the device at the Input Report addresses -+ // specified in ACPI." -+ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; -+ struct { -+ struct hidspi_header header; -+ union { -+ struct hidspi_device_descriptor device_desc; -+ u32 data[16]; -+ }; -+ } resp = { 0 }; -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { -+ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); -+ return -ENOMSG; -+ } -+ -+ // "4. The host shall then write an Output Report to the device at the Output Report Address -+ // specified in ACPI, requesting the Device Descriptor from the device." -+ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; -+ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); -+ -+ // "5. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing the Device Descriptor." -+ size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { -+ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "6. The host shall read the Device Descriptor from the Input Report addresses specified -+ // in ACPI." -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ memset(&resp, 0, sizeof(resp)); -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { -+ pci_err(ithc->pci, "received type %i instead of device descriptor\n", -+ resp.header.type); -+ return -ENOMSG; -+ } -+ struct hidspi_device_descriptor *d = &resp.device_desc; -+ if (resp.header.len < sizeof(*d)) { -+ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", -+ resp.header.len); -+ return -EMSGSIZE; -+ } -+ if (d->wDeviceDescLength != sizeof(*d)) { -+ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", -+ d->wDeviceDescLength); -+ return -EMSGSIZE; -+ } -+ -+ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", -+ d->bcdVersion, d->wReportDescLength, -+ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, -+ d->wVendorID, d->wProductID, d->wVersionID, -+ d->wFlags, d->dwReserved); -+ -+ ithc->vendor_id = d->wVendorID; -+ ithc->product_id = d->wProductID; -+ ithc->product_rev = d->wVersionID; -+ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, -+ d->wReportDescLength + sizeof(struct hidspi_header)); -+ ithc->max_tx_size = d->wMaxOutputLength; -+ ithc->have_config = true; -+ -+ // "7. The device and host shall then enter their "Ready" states - where the device may -+ // begin sending Input Reports, and the device shall be prepared for Output Reports from -+ // the host." -+ -+ return 0; -+} -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); -+ ithc_log_regs(ithc); -+ -+ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, -+ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); -+ -+ // TODO Do we need to set any of the following bits here? -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); -+ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ ithc_log_regs(ithc); -+ -+ return 0; -+} -+ -+void ithc_quickspi_exit(struct ithc *ithc) -+{ -+ // TODO Should we send HIDSPI 'power off' command? -+ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; -+ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; -+ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() -+} -+ -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct hidspi_header *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // TODO Do we need to handle HIDSPI packet fragmentation? -+ if (len < sizeof(*hdr) + hdr->len) -+ return -EMSGSIZE; -+ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) -+ return -EMSGSIZE; -+ -+ switch (hdr->type) { -+ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: -+ // TODO "When the device detects an error condition, it may interrupt and make -+ // available to the host an Input Report containing an unsolicited Reset Response. -+ // After receiving an unsolicited Reset Response, the host shall initiate the -+ // request procedure from step (4) in the [HIDSPI initialization] process." -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = hdr + 1; -+ dest->size = hdr->len; -+ return 0; -+ case HIDSPI_INPUT_TYPE_DATA: -+ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: -+ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_IGNORE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct hidspi_header *hdr = dest; -+ -+ size_t src_size = src->size; -+ const u8 *src_data = src->data; -+ u8 type; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; -+ src_size = 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ u8 id = 0; -+ if (src_size) { -+ id = *src_data++; -+ src_size--; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->type = type; -+ hdr->len = (u16)src_size; -+ hdr->id = id; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h -new file mode 100644 -index 000000000000..74d882f6b2f0 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.h -@@ -0,0 +1,39 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+struct ithc_acpi_config { -+ bool has_config: 1; -+ bool has_input_report_header_address: 1; -+ bool has_input_report_body_address: 1; -+ bool has_output_report_body_address: 1; -+ bool has_read_opcode: 1; -+ bool has_write_opcode: 1; -+ bool has_read_mode: 1; -+ bool has_write_mode: 1; -+ bool has_spi_frequency: 1; -+ bool has_limit_packet_size: 1; -+ bool has_tx_delay: 1; -+ bool has_active_ltr: 1; -+ bool has_idle_ltr: 1; -+ u32 input_report_header_address; -+ u32 input_report_body_address; -+ u32 output_report_body_address; -+ u8 read_opcode; -+ u8 write_opcode; -+ u8 read_mode; -+ u8 write_mode; -+ u32 spi_frequency; -+ u32 limit_packet_size; -+ u32 tx_delay; // us/10 // TODO use? -+ u32 active_ltr; // ns/1024 -+ u32 idle_ltr; // ns/1024 -+}; -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+void ithc_quickspi_exit(struct ithc *ithc); -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c -new file mode 100644 -index 000000000000..c0f13506af20 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.c -@@ -0,0 +1,154 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writel((readl(reg) & ~mask) | (val & mask), reg); -+} -+ -+void bitsb(__iomem u8 *reg, u8 mask, u8 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writeb((readb(reg) & ~mask) | (val & mask), reg); -+} -+ -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) -+{ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ u32 x; -+ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) -+{ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ u8 x; -+ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) -+{ -+ unsigned int s = 0; -+ u64 v = *ns; -+ while (v > 0x3ff) { -+ s++; -+ v >>= 5; -+ } -+ if (s > 5) { -+ s = 5; -+ v = 0x3ff; -+ } -+ *val = v; -+ *scale = s; -+ *ns = v << (5 * s); -+} -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) -+{ -+ unsigned int active_val, active_scale, idle_val, idle_scale; -+ calc_ltr(&active_ltr_ns, &active_val, &active_scale); -+ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); -+ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", -+ active_ltr_ns, idle_ltr_ns); -+ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | -+ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | -+ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), -+ &ithc->regs->ltr_config); -+} -+ -+void ithc_set_ltr_idle(struct ithc *ithc) -+{ -+ u32 ltr = readl(&ithc->regs->ltr_config); -+ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { -+ case LTR_CONFIG_STATUS_IDLE: -+ break; -+ case LTR_CONFIG_STATUS_ACTIVE: -+ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); -+ break; -+ default: -+ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); -+ break; -+ } -+} -+ -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) -+{ -+ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) -+ return -EINVAL; -+ static const char * const modes[] = { "single", "dual", "quad" }; -+ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", -+ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), -+ modes[read_mode], modes[write_mode]); -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | -+ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | -+ SPI_CONFIG_CLKDIV_8, -+ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | -+ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | -+ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); -+ return 0; -+} -+ -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) -+{ -+ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); -+ if (size > sizeof(ithc->regs->spi_cmd.data)) -+ return -EINVAL; -+ -+ // Wait if the device is still busy. -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ // Clear result flags. -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ -+ // Init SPI command data. -+ writeb(command, &ithc->regs->spi_cmd.code); -+ writew(size, &ithc->regs->spi_cmd.size); -+ writel(offset, &ithc->regs->spi_cmd.offset); -+ u32 *p = data, n = (size + 3) / 4; -+ for (u32 i = 0; i < n; i++) -+ writel(p[i], &ithc->regs->spi_cmd.data[i]); -+ -+ // Start transmission. -+ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ -+ // Read response. -+ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) -+ return -EIO; -+ if (readw(&ithc->regs->spi_cmd.size) != size) -+ return -EMSGSIZE; -+ for (u32 i = 0; i < n; i++) -+ p[i] = readl(&ithc->regs->spi_cmd.data[i]); -+ -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h -new file mode 100644 -index 000000000000..4f541fe533fa ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.h -@@ -0,0 +1,211 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) -+#define LTR_CONFIG_TOGGLE BIT(1) -+#define LTR_CONFIG_ENABLE_IDLE BIT(2) -+#define LTR_CONFIG_APPLY BIT(3) -+#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) -+#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) -+#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) -+#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) -+#define LTR_CONFIG_STATUS_ACTIVE BIT(30) -+#define LTR_CONFIG_STATUS_IDLE BIT(31) -+ -+#define CONTROL_QUIESCE BIT(1) -+#define CONTROL_IS_QUIESCED BIT(2) -+#define CONTROL_NRESET BIT(3) -+#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) -+#define CONTROL_READY BIT(29) -+ -+#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) -+#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) -+#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) -+#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) -+#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) -+#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write -+#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) -+ -+#define SPI_CLK_FREQ_BASE 125000000 -+#define SPI_MODE_SINGLE 0 -+#define SPI_MODE_DUAL 1 -+#define SPI_MODE_QUAD 2 -+ -+#define ERROR_CONTROL_UNKNOWN_0 BIT(0) -+#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs -+#define ERROR_CONTROL_UNKNOWN_2 BIT(2) -+#define ERROR_CONTROL_UNKNOWN_3 BIT(3) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? -+#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs -+ -+#define ERROR_STATUS_DMA BIT(28) -+#define ERROR_STATUS_SPI BIT(30) -+ -+#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message -+#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) -+#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) -+#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) -+#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) -+#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) -+#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) -+ -+#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define SPI_CMD_CONTROL_IRQ BIT(1) -+ -+#define SPI_CMD_CODE_READ 4 -+#define SPI_CMD_CODE_WRITE 6 -+ -+#define SPI_CMD_STATUS_DONE BIT(0) -+#define SPI_CMD_STATUS_ERROR BIT(1) -+#define SPI_CMD_STATUS_BUSY BIT(3) -+ -+#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define DMA_TX_CONTROL_IRQ BIT(3) -+ -+#define DMA_TX_STATUS_DONE BIT(0) -+#define DMA_TX_STATUS_ERROR BIT(1) -+#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) -+#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? -+ -+#define INPUT_HEADER_VERSION(x) ((x) & 0xf) -+#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) -+#define INPUT_HEADER_SYNC(x) ((x) >> 24) -+#define INPUT_HEADER_VERSION_VALUE 3 -+#define INPUT_HEADER_SYNC_VALUE 0x5a -+ -+#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) -+#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) -+ -+#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) -+#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) -+#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) -+#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) -+#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) -+#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) -+#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) -+ -+#define DMA_RX_CONTROL_ENABLE BIT(0) -+#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only -+#define DMA_RX_CONTROL_IRQ_DATA BIT(5) -+ -+#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? -+#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? -+#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices -+ -+#define DMA_RX_WRAP_FLAG BIT(7) -+ -+#define DMA_RX_STATUS_ERROR BIT(3) -+#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) -+#define DMA_RX_STATUS_HAVE_DATA BIT(5) -+#define DMA_RX_STATUS_ENABLED BIT(8) -+ -+#define INIT_UNKNOWN_GUC_2 BIT(2) -+#define INIT_UNKNOWN_3 BIT(3) -+#define INIT_UNKNOWN_GUC_4 BIT(4) -+#define INIT_UNKNOWN_5 BIT(5) -+#define INIT_UNKNOWN_31 BIT(31) -+ -+// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. -+#define COUNTER_RESET BIT(31) -+ -+struct ithc_registers { -+ /* 0000 */ u32 _unknown_0000[5]; -+ /* 0014 */ u32 ltr_config; -+ /* 0018 */ u32 _unknown_0018[1018]; -+ /* 1000 */ u32 _unknown_1000; -+ /* 1004 */ u32 _unknown_1004; -+ /* 1008 */ u32 control_bits; -+ /* 100c */ u32 _unknown_100c; -+ /* 1010 */ u32 spi_config; -+ struct { -+ /* 1014/1018/101c */ u8 header; -+ /* 1015/1019/101d */ u8 quad; -+ /* 1016/101a/101e */ u8 dual; -+ /* 1017/101b/101f */ u8 single; -+ } opcode[3]; -+ /* 1020 */ u32 error_control; -+ /* 1024 */ u32 error_status; // write to clear -+ /* 1028 */ u32 error_flags; // write to clear -+ /* 102c */ u32 _unknown_102c[5]; -+ struct { -+ /* 1040 */ u8 control; -+ /* 1041 */ u8 code; -+ /* 1042 */ u16 size; -+ /* 1044 */ u32 status; // write to clear -+ /* 1048 */ u32 offset; -+ /* 104c */ u32 data[16]; -+ /* 108c */ u32 _unknown_108c; -+ } spi_cmd; -+ struct { -+ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1098 */ u8 control; -+ /* 1099 */ u8 _unknown_1099; -+ /* 109a */ u8 _unknown_109a; -+ /* 109b */ u8 num_prds; -+ /* 109c */ u32 status; // write to clear -+ /* 10a0 */ u32 _unknown_10a0[5]; -+ /* 10b4 */ u32 spi_addr; -+ } dma_tx; -+ /* 10b8 */ u32 spi_header_addr; -+ union { -+ /* 10bc */ u32 irq_cause; // in legacy THC mode -+ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) -+ }; -+ /* 10c0 */ u32 _unknown_10c0[8]; -+ /* 10e0 */ u32 _unknown_10e0_counters[3]; -+ /* 10ec */ u32 quickspi_config1; -+ /* 10f0 */ u32 quickspi_config2; -+ /* 10f4 */ u32 _unknown_10f4[3]; -+ struct { -+ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1108/1208 */ u8 num_bufs; -+ /* 1109/1209 */ u8 num_prds; -+ /* 110a/120a */ u16 _unknown_110a; -+ /* 110c/120c */ u8 control; -+ /* 110d/120d */ u8 head; -+ /* 110e/120e */ u8 tail; -+ /* 110f/120f */ u8 control2; -+ /* 1110/1210 */ u32 status; // write to clear -+ /* 1114/1214 */ u32 _unknown_1114; -+ /* 1118/1218 */ u64 _unknown_1118_guc_addr; -+ /* 1120/1220 */ u32 _unknown_1120_guc; -+ /* 1124/1224 */ u32 _unknown_1124_guc; -+ /* 1128/1228 */ u32 init_unknown; -+ /* 112c/122c */ u32 _unknown_112c; -+ /* 1130/1230 */ u64 _unknown_1130_guc_addr; -+ /* 1138/1238 */ u32 _unknown_1138_guc; -+ /* 113c/123c */ u32 _unknown_113c; -+ /* 1140/1240 */ u32 _unknown_1140_guc; -+ /* 1144/1244 */ u32 _unknown_1144[11]; -+ /* 1170/1270 */ u32 spi_addr; -+ /* 1174/1274 */ u32 _unknown_1174[11]; -+ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; -+ /* 11b8/12b8 */ u32 _unknown_11b8[18]; -+ } dma_rx[2]; -+}; -+static_assert(sizeof(struct ithc_registers) == 0x1300); -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val); -+void bitsb(__iomem u8 *reg, u8 mask, u8 val); -+#define bitsl_set(reg, x) bitsl(reg, x, x) -+#define bitsb_set(reg, x) bitsb(reg, x, x) -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); -+void ithc_set_ltr_idle(struct ithc *ithc); -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); -+ -diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h -new file mode 100644 -index 000000000000..aec320d4e945 ---- /dev/null -+++ b/drivers/hid/ithc/ithc.h -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEVNAME "ithc" -+#define DEVFULLNAME "Intel Touch Host Controller" -+ -+#undef pr_fmt -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) -+#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) -+ -+#define NUM_RX_BUF 16 -+ -+// PCI device IDs: -+// Lakefield -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 -+// Tiger Lake -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 -+// Alder Lake -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 -+// Raptor Lake -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 -+// Meteor Lake -+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b -+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b -+ -+struct ithc; -+ -+#include "ithc-regs.h" -+#include "ithc-hid.h" -+#include "ithc-dma.h" -+#include "ithc-legacy.h" -+#include "ithc-quickspi.h" -+#include "ithc-debug.h" -+ -+struct ithc { -+ char phys[32]; -+ struct pci_dev *pci; -+ int irq; -+ struct task_struct *poll_thread; -+ struct timer_list idle_timer; -+ -+ struct ithc_registers __iomem *regs; -+ struct ithc_registers *prev_regs; // for debugging -+ struct ithc_dma_rx dma_rx[2]; -+ struct ithc_dma_tx dma_tx; -+ struct ithc_hid hid; -+ -+ bool use_quickspi; -+ bool have_config; -+ u16 vendor_id; -+ u16 product_id; -+ u32 product_rev; -+ u32 max_rx_size; -+ u32 max_tx_size; -+ u32 legacy_touch_cfg; -+}; -+ -+int ithc_reset(struct ithc *ithc); -+ --- -2.47.1 - diff --git a/patches/6.14-rc4/0007-surface-sam-over-hid.patch b/patches/6.14-rc4/0007-surface-sam-over-hid.patch deleted file mode 100644 index a65acd8e4f..0000000000 --- a/patches/6.14-rc4/0007-surface-sam-over-hid.patch +++ /dev/null @@ -1,308 +0,0 @@ -From 064893f3e33bd77cecece7ea4047b3a6e1147fe2 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 25 Jul 2020 17:19:53 +0200 -Subject: [PATCH] i2c: acpi: Implement RawBytes read access - -Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C -device via a generic serial bus operation region and RawBytes read -access. On the Surface Book 1, this access is required to turn on (and -off) the discrete GPU. - -Multiple things are to note here: - -a) The RawBytes access is device/driver dependent. The ACPI - specification states: - - > Raw accesses assume that the writer has knowledge of the bus that - > the access is made over and the device that is being accessed. The - > protocol may only ensure that the buffer is transmitted to the - > appropriate driver, but the driver must be able to interpret the - > buffer to communicate to a register. - - Thus this implementation may likely not work on other devices - accessing I2C via the RawBytes accessor type. - -b) The MSHW0030 I2C device is an HID-over-I2C device which seems to - serve multiple functions: - - 1. It is the main access point for the legacy-type Surface Aggregator - Module (also referred to as SAM-over-HID, as opposed to the newer - SAM-over-SSH/UART). It has currently not been determined on how - support for the legacy SAM should be implemented. Likely via a - custom HID driver. - - 2. It seems to serve as the HID device for the Integrated Sensor Hub. - This might complicate matters with regards to implementing a - SAM-over-HID driver required by legacy SAM. - -In light of this, the simplest approach has been chosen for now. -However, it may make more sense regarding breakage and compatibility to -either provide functionality for replacing or enhancing the default -operation region handler via some additional API functions, or even to -completely blacklist MSHW0030 from the I2C core and provide a custom -driver for it. - -Replacing/enhancing the default operation region handler would, however, -either require some sort of secondary driver and access point for it, -from which the new API functions would be called and the new handler -(part) would be installed, or hard-coding them via some sort of -quirk-like interface into the I2C core. - -Signed-off-by: Maximilian Luz -Patchset: surface-sam-over-hid ---- - drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index 14ae0cfc325e..6197c5252d2a 100644 ---- a/drivers/i2c/i2c-core-acpi.c -+++ b/drivers/i2c/i2c-core-acpi.c -@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, - return (ret == 1) ? 0 : -EIO; - } - -+static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, -+ u8 *data, u8 data_len) -+{ -+ struct i2c_msg msgs[1]; -+ int ret; -+ -+ msgs[0].addr = client->addr; -+ msgs[0].flags = client->flags; -+ msgs[0].len = data_len + 1; -+ msgs[0].buf = data; -+ -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret < 0) { -+ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* 1 transfer must have completed successfully */ -+ return (ret == 1) ? 0 : -EIO; -+} -+ - static acpi_status - i2c_acpi_space_handler(u32 function, acpi_physical_address command, - u32 bits, u64 *value64, -@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, - } - break; - -+ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: -+ if (action == ACPI_READ) { -+ dev_warn(&adapter->dev, -+ "protocol 0x%02x not supported for client 0x%02x\n", -+ accessor_type, client->addr); -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } else { -+ status = acpi_gsb_i2c_write_raw_bytes(client, -+ gsb->data, info->access_length); -+ } -+ break; -+ - default: - dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", - accessor_type, client->addr); --- -2.47.1 - -From f6714cb9a95aeec3379336df70e7cc8d9537f727 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 13 Feb 2021 16:41:18 +0100 -Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch - -Add driver exposing the discrete GPU power-switch of the Microsoft -Surface Book 1 to user-space. - -On the Surface Book 1, the dGPU power is controlled via the Surface -System Aggregator Module (SAM). The specific SAM-over-HID command for -this is exposed via ACPI. This module provides a simple driver exposing -the ACPI call via a sysfs parameter to user-space, so that users can -easily power-on/-off the dGPU. - -Patchset: surface-sam-over-hid ---- - drivers/platform/surface/Kconfig | 7 + - drivers/platform/surface/Makefile | 1 + - .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ - 3 files changed, 144 insertions(+) - create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c - -diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index b629e82af97c..68656e8f309e 100644 ---- a/drivers/platform/surface/Kconfig -+++ b/drivers/platform/surface/Kconfig -@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH - Select M or Y here, if you want to provide tablet-mode switch input - events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. - -+config SURFACE_BOOK1_DGPU_SWITCH -+ tristate "Surface Book 1 dGPU Switch Driver" -+ depends on SYSFS -+ help -+ This driver provides a sysfs switch to set the power-state of the -+ discrete GPU found on the Microsoft Surface Book 1. -+ - config SURFACE_DTX - tristate "Surface DTX (Detachment System) Driver" - depends on SURFACE_AGGREGATOR -diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 ---- a/drivers/platform/surface/Makefile -+++ b/drivers/platform/surface/Makefile -@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o - obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o - obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o - obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o -+obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o - obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o - obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o - obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o -diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c -new file mode 100644 -index 000000000000..68db237734a1 ---- /dev/null -+++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c -@@ -0,0 +1,136 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include -+#include -+#include -+ -+/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ -+static const guid_t dgpu_sw_guid = -+ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, -+ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); -+ -+#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" -+#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" -+#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" -+ -+static int sb1_dgpu_sw_dsmcall(void) -+{ -+ union acpi_object *obj; -+ acpi_handle handle; -+ acpi_status status; -+ -+ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); -+ if (status) -+ return -EINVAL; -+ -+ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); -+ if (!obj) -+ return -EINVAL; -+ -+ ACPI_FREE(obj); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgon(struct device *dev) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); -+ if (status) { -+ dev_err(dev, "failed to run HGON: %d\n", status); -+ return -EINVAL; -+ } -+ -+ ACPI_FREE(buf.pointer); -+ -+ dev_info(dev, "turned-on dGPU via HGON\n"); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgof(struct device *dev) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); -+ if (status) { -+ dev_err(dev, "failed to run HGOF: %d\n", status); -+ return -EINVAL; -+ } -+ -+ ACPI_FREE(buf.pointer); -+ -+ dev_info(dev, "turned-off dGPU via HGOF\n"); -+ return 0; -+} -+ -+static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool value; -+ int status; -+ -+ status = kstrtobool(buf, &value); -+ if (status < 0) -+ return status; -+ -+ if (!value) -+ return 0; -+ -+ status = sb1_dgpu_sw_dsmcall(); -+ -+ return status < 0 ? status : len; -+} -+static DEVICE_ATTR_WO(dgpu_dsmcall); -+ -+static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool power; -+ int status; -+ -+ status = kstrtobool(buf, &power); -+ if (status < 0) -+ return status; -+ -+ if (power) -+ status = sb1_dgpu_sw_hgon(dev); -+ else -+ status = sb1_dgpu_sw_hgof(dev); -+ -+ return status < 0 ? status : len; -+} -+static DEVICE_ATTR_WO(dgpu_power); -+ -+static struct attribute *sb1_dgpu_sw_attrs[] = { -+ &dev_attr_dgpu_dsmcall.attr, -+ &dev_attr_dgpu_power.attr, -+ NULL -+}; -+ATTRIBUTE_GROUPS(sb1_dgpu_sw); -+ -+/* -+ * The dGPU power seems to be actually handled by MSHW0040. However, that is -+ * also the power-/volume-button device with a mainline driver. So let's use -+ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. -+ */ -+static const struct acpi_device_id sb1_dgpu_sw_match[] = { -+ { "MSHW0041", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); -+ -+static struct platform_driver sb1_dgpu_sw = { -+ .driver = { -+ .name = "surfacebook1_dgpu_switch", -+ .acpi_match_table = sb1_dgpu_sw_match, -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ .dev_groups = sb1_dgpu_sw_groups, -+ }, -+}; -+module_platform_driver(sb1_dgpu_sw); -+ -+MODULE_AUTHOR("Maximilian Luz "); -+MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); -+MODULE_LICENSE("GPL"); --- -2.47.1 - diff --git a/patches/6.14-rc4/0008-surface-button.patch b/patches/6.14-rc4/0008-surface-button.patch deleted file mode 100644 index 934e9156d2..0000000000 --- a/patches/6.14-rc4/0008-surface-button.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 9d06bf6cc92b13c9e4c4781484b82804c4150d80 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Tue, 5 Oct 2021 00:05:09 +1100 -Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices - -The power button on the AMD variant of the Surface Laptop uses the -same MSHW0040 device ID as the 5th and later generation of Surface -devices, however they report 0 for their OEM platform revision. As the -_DSM does not exist on the devices requiring special casing, check for -the existance of the _DSM to determine if soc_button_array should be -loaded. - -Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") -Co-developed-by: Maximilian Luz - -Signed-off-by: Sachi King -Patchset: surface-button ---- - drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- - 1 file changed, 8 insertions(+), 25 deletions(-) - -diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index 5c5d407fe965..4e1bfe90e730 100644 ---- a/drivers/input/misc/soc_button_array.c -+++ b/drivers/input/misc/soc_button_array.c -@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { - * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned - * devices use MSHW0040 for power and volume buttons, however the way they - * have to be addressed differs. Make sure that we only load this drivers -- * for the correct devices by checking the OEM Platform Revision provided by -- * the _DSM method. -+ * for the correct devices by checking if the OEM Platform Revision DSM call -+ * exists. - */ - #define MSHW0040_DSM_REVISION 0x01 - #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision -@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = - static int soc_device_check_MSHW0040(struct device *dev) - { - acpi_handle handle = ACPI_HANDLE(dev); -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, NULL, -- ACPI_TYPE_INTEGER); -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- /* -- * If the revision is zero here, the _DSM evaluation has failed. This -- * indicates that we have a Pro 4 or Book 1 and this driver should not -- * be used. -- */ -- if (oem_platform_rev == 0) -- return -ENODEV; -+ bool exists; - -- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); -+ // check if OEM platform revision DSM call exists -+ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - -- return 0; -+ return exists ? 0 : -ENODEV; - } - - /* --- -2.47.1 - -From f870bb021693abb7ea617c323216c615151b62e1 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Tue, 5 Oct 2021 00:22:57 +1100 -Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd - variant - -The AMD variant of the Surface Laptop report 0 for their OEM platform -revision. The Surface devices that require the surfacepro3_button -driver do not have the _DSM that gets the OEM platform revision. If the -method does not exist, load surfacepro3_button. - -Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") -Co-developed-by: Maximilian Luz - -Signed-off-by: Sachi King -Patchset: surface-button ---- - drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- - 1 file changed, 6 insertions(+), 24 deletions(-) - -diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 ---- a/drivers/platform/surface/surfacepro3_button.c -+++ b/drivers/platform/surface/surfacepro3_button.c -@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) - /* - * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device - * ID (MSHW0040) for the power/volume buttons. Make sure this is the right -- * device by checking for the _DSM method and OEM Platform Revision. -+ * device by checking for the _DSM method and OEM Platform Revision DSM -+ * function. - * - * Returns true if the driver should bind to this device, i.e. the device is - * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. -@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) - static bool surface_button_check_MSHW0040(struct acpi_device *dev) - { - acpi_handle handle = dev->handle; -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, -- NULL, ACPI_TYPE_INTEGER); -- -- /* -- * If evaluating the _DSM fails, the method is not present. This means -- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we -- * should use this driver. We use revision 0 indicating it is -- * unavailable. -- */ -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); - -- return oem_platform_rev == 0; -+ // make sure that OEM platform revision DSM call does not exist -+ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - } - - --- -2.47.1 - diff --git a/patches/6.14-rc4/0009-surface-typecover.patch b/patches/6.14-rc4/0009-surface-typecover.patch deleted file mode 100644 index 7cc1b3eb95..0000000000 --- a/patches/6.14-rc4/0009-surface-typecover.patch +++ /dev/null @@ -1,575 +0,0 @@ -From df8f9981df6f0a92100266397ded155314efc7e3 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 18 Feb 2023 01:02:49 +0100 -Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 - Type-Cover - -The touchpad on the Type-Cover of the Surface Go 3 is sometimes not -being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this -issue. - -More specifically, the device in question is a fairly standard modern -touchpad with pointer and touchpad input modes. During setup, the device -needs to be switched from pointer- to touchpad-mode (which is done in -hid-multitouch) to fully utilize it as intended. Unfortunately, however, -this seems to occasionally fail silently, leaving the device in -pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. - -Link: https://github.com/linux-surface/linux-surface/issues/1059 -Signed-off-by: Maximilian Luz -Patchset: surface-typecover ---- - drivers/usb/core/quirks.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 13171454f959..a83beefd25f3 100644 ---- a/drivers/usb/core/quirks.c -+++ b/drivers/usb/core/quirks.c -@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { - /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ - { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, - -+ /* Microsoft Surface Go 3 Type-Cover */ -+ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, -+ - /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ - { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, - --- -2.47.1 - -From 3aa9fc5fd7faed0bd5948e80e6ef6173c32a83ca Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 5 Nov 2020 13:09:45 +0100 -Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when - suspending - -The Type Cover for Microsoft Surface devices supports a special usb -control request to disable or enable the built-in keyboard backlight. -On Windows, this request happens when putting the device into suspend or -resuming it, without it the backlight of the Type Cover will remain -enabled for some time even though the computer is suspended, which looks -weird to the user. - -So add support for this special usb control request to hid-multitouch, -which is the driver that's handling the Type Cover. - -The reason we have to use a pm_notifier for this instead of the usual -suspend/resume methods is that those won't get called in case the usb -device is already autosuspended. - -Also, if the device is autosuspended, we have to briefly autoresume it -in order to send the request. Doing that should be fine, the usb-core -driver does something similar during suspend inside choose_wakeup(). - -To make sure we don't send that request to every device but only to -devices which support it, add a new quirk -MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk -is only enabled for the usb id of the Surface Pro 2017 Type Cover, which -is where I confirmed that it's working. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- - 1 file changed, 98 insertions(+), 2 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e936019d21fe..08fee06fb5fc 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -34,7 +34,10 @@ - #include - #include - #include -+#include - #include -+#include -+#include - #include - #include - #include -@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); - MODULE_LICENSE("GPL"); - - #include "hid-ids.h" -+#include "usbhid/usbhid.h" - - /* quirks to control the device */ - #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) -@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 - - #define MT_BUTTONTYPE_CLICKPAD 0 - -+#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+ - enum latency_mode { - HID_LATENCY_NORMAL = 0, - HID_LATENCY_HIGH = 1, -@@ -168,6 +175,8 @@ struct mt_device { - - struct list_head applications; - struct list_head reports; -+ -+ struct notifier_block pm_notifier; - }; - - static void mt_post_parse_default_settings(struct mt_device *td, -@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_GOOGLE 0x0111 - #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 - #define MT_CLS_SMART_TECH 0x0113 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 - #define MT_CLS_SIS 0x0457 - - #define MT_DEFAULT_MAXCONTACT 10 -@@ -402,6 +412,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE, - }, -+ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, -+ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | -+ MT_QUIRK_ALWAYS_VALID | -+ MT_QUIRK_IGNORE_DUPLICATES | -+ MT_QUIRK_HOVERING | -+ MT_QUIRK_CONTACT_CNT_ACCURATE | -+ MT_QUIRK_STICKY_FINGERS | -+ MT_QUIRK_WIN8_PTP_BUTTONS, -+ .export_all_inputs = true -+ }, - { } - }; - -@@ -1751,6 +1771,69 @@ static void mt_expired_timeout(struct timer_list *t) - clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); - } - -+static void get_type_cover_backlight_field(struct hid_device *hdev, -+ struct hid_field **field) -+{ -+ struct hid_report_enum *rep_enum; -+ struct hid_report *rep; -+ struct hid_field *cur_field; -+ int i, j; -+ -+ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; -+ list_for_each_entry(rep, &rep_enum->report_list, list) { -+ for (i = 0; i < rep->maxfield; i++) { -+ cur_field = rep->field[i]; -+ -+ for (j = 0; j < cur_field->maxusage; j++) { -+ if (cur_field->usage[j].hid -+ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { -+ *field = cur_field; -+ return; -+ } -+ } -+ } -+ } -+} -+ -+static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) -+{ -+ struct usb_device *udev = hid_to_usb_dev(hdev); -+ struct hid_field *field = NULL; -+ -+ /* Wake up the device in case it's already suspended */ -+ pm_runtime_get_sync(&udev->dev); -+ -+ get_type_cover_backlight_field(hdev, &field); -+ if (!field) { -+ hid_err(hdev, "couldn't find backlight field\n"); -+ goto out; -+ } -+ -+ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; -+ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); -+ -+out: -+ pm_runtime_put_sync(&udev->dev); -+} -+ -+static int mt_pm_notifier(struct notifier_block *notifier, -+ unsigned long pm_event, -+ void *unused) -+{ -+ struct mt_device *td = -+ container_of(notifier, struct mt_device, pm_notifier); -+ struct hid_device *hdev = td->hdev; -+ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { -+ if (pm_event == PM_SUSPEND_PREPARE) -+ update_keyboard_backlight(hdev, 0); -+ else if (pm_event == PM_POST_SUSPEND) -+ update_keyboard_backlight(hdev, 1); -+ } -+ -+ return NOTIFY_DONE; -+} -+ - static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - { - int ret, i; -@@ -1774,6 +1857,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; - hid_set_drvdata(hdev, td); - -+ td->pm_notifier.notifier_call = mt_pm_notifier; -+ register_pm_notifier(&td->pm_notifier); -+ - INIT_LIST_HEAD(&td->applications); - INIT_LIST_HEAD(&td->reports); - -@@ -1812,8 +1898,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - timer_setup(&td->release_timer, mt_expired_timeout, 0); - - ret = hid_parse(hdev); -- if (ret != 0) -+ if (ret != 0) { -+ unregister_pm_notifier(&td->pm_notifier); - return ret; -+ } - - if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) - mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1822,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - hdev->quirks |= HID_QUIRK_NOGET; - - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); -- if (ret) -+ if (ret) { -+ unregister_pm_notifier(&td->pm_notifier); - return ret; -+ } - - ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); - if (ret) -@@ -1873,6 +1963,7 @@ static void mt_remove(struct hid_device *hdev) - { - struct mt_device *td = hid_get_drvdata(hdev); - -+ unregister_pm_notifier(&td->pm_notifier); - del_timer_sync(&td->release_timer); - - sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2299,6 +2390,11 @@ static const struct hid_device_id mt_devices[] = { - MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, - USB_DEVICE_ID_XIROKU_CSR2) }, - -+ /* Microsoft Surface type cover */ -+ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, -+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, -+ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, -+ - /* Google MT devices */ - { .driver_data = MT_CLS_GOOGLE, - HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, --- -2.47.1 - -From c88ebc0ed1f21ec7ad52aa4fb2c48226603d7596 Mon Sep 17 00:00:00 2001 -From: PJungkamp -Date: Fri, 25 Feb 2022 12:04:25 +0100 -Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet - switch - -The Surface Pro Type Cover has several non standard HID usages in it's -hid report descriptor. -I noticed that, upon folding the typecover back, a vendor specific range -of 4 32 bit integer hid usages is transmitted. -Only the first byte of the message seems to convey reliable information -about the keyboard state. - -0x22 => Normal (keys enabled) -0x33 => Folded back (keys disabled) -0x53 => Rotated left/right side up (keys disabled) -0x13 => Cover closed (keys disabled) -0x43 => Folded back and Tablet upside down (keys disabled) -This list may not be exhaustive. - -The tablet mode switch will be disabled for a value of 0x22 and enabled -on any other value. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ - 1 file changed, 122 insertions(+), 26 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 08fee06fb5fc..f6664049f46d 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); - #define MT_BUTTONTYPE_CLICKPAD 0 - - #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 -+#define MS_TYPE_COVER_APPLICATION 0xff050050 - - enum latency_mode { - HID_LATENCY_NORMAL = 0, -@@ -414,6 +417,7 @@ static const struct mt_class mt_classes[] = { - }, - { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, - .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | -+ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_IGNORE_DUPLICATES | - MT_QUIRK_HOVERING | -@@ -1395,6 +1399,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - field->application != HID_CP_CONSUMER_CONTROL && - field->application != HID_GD_WIRELESS_RADIO_CTLS && - field->application != HID_GD_SYSTEM_MULTIAXIS && -+ !(field->application == MS_TYPE_COVER_APPLICATION && -+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && - !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && - application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) - return -1; -@@ -1422,6 +1429,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - return 1; - } - -+ /* -+ * The Microsoft Surface Pro Typecover has a non-standard HID -+ * tablet mode switch on a vendor specific usage page with vendor -+ * specific usage. -+ */ -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ usage->type = EV_SW; -+ usage->code = SW_TABLET_MODE; -+ *max = SW_MAX; -+ *bit = hi->input->swbit; -+ return 1; -+ } -+ - if (rdata->is_mt_collection) - return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, - application); -@@ -1443,6 +1465,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, - { - struct mt_device *td = hid_get_drvdata(hdev); - struct mt_report_data *rdata; -+ struct input_dev *input; - - rdata = mt_find_report_data(td, field->report); - if (rdata && rdata->is_mt_collection) { -@@ -1450,6 +1473,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, - return -1; - } - -+ /* -+ * We own an input device which acts as a tablet mode switch for -+ * the Surface Pro Typecover. -+ */ -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ input = hi->input; -+ input_set_capability(input, EV_SW, SW_TABLET_MODE); -+ input_report_switch(input, SW_TABLET_MODE, 0); -+ return -1; -+ } -+ - /* let hid-core decide for the others */ - return 0; - } -@@ -1459,11 +1495,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, - { - struct mt_device *td = hid_get_drvdata(hid); - struct mt_report_data *rdata; -+ struct input_dev *input; - - rdata = mt_find_report_data(td, field->report); - if (rdata && rdata->is_mt_collection) - return mt_touch_event(hid, field, usage, value); - -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ input = field->hidinput->input; -+ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); -+ input_sync(input); -+ return 1; -+ } -+ - return 0; - } - -@@ -1641,6 +1687,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) - app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; - } - -+static int get_type_cover_field(struct hid_report_enum *rep_enum, -+ struct hid_field **field, int usage) -+{ -+ struct hid_report *rep; -+ struct hid_field *cur_field; -+ int i, j; -+ -+ list_for_each_entry(rep, &rep_enum->report_list, list) { -+ for (i = 0; i < rep->maxfield; i++) { -+ cur_field = rep->field[i]; -+ if (cur_field->application != MS_TYPE_COVER_APPLICATION) -+ continue; -+ for (j = 0; j < cur_field->maxusage; j++) { -+ if (cur_field->usage[j].hid == usage) { -+ *field = cur_field; -+ return true; -+ } -+ } -+ } -+ } -+ return false; -+} -+ -+static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) -+{ -+ struct hid_field *field; -+ -+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], -+ &field, -+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { -+ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); -+ } else { -+ hid_err(hdev, "couldn't find tablet mode field\n"); -+ } -+} -+ - static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) - { - struct mt_device *td = hid_get_drvdata(hdev); -@@ -1689,6 +1771,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); - break; -+ case MS_TYPE_COVER_APPLICATION: -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { -+ suffix = "Tablet Mode Switch"; -+ request_type_cover_tablet_mode_switch(hdev); -+ break; -+ } -+ fallthrough; - default: - suffix = "UNKNOWN"; - break; -@@ -1771,30 +1860,6 @@ static void mt_expired_timeout(struct timer_list *t) - clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); - } - --static void get_type_cover_backlight_field(struct hid_device *hdev, -- struct hid_field **field) --{ -- struct hid_report_enum *rep_enum; -- struct hid_report *rep; -- struct hid_field *cur_field; -- int i, j; -- -- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; -- list_for_each_entry(rep, &rep_enum->report_list, list) { -- for (i = 0; i < rep->maxfield; i++) { -- cur_field = rep->field[i]; -- -- for (j = 0; j < cur_field->maxusage; j++) { -- if (cur_field->usage[j].hid -- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { -- *field = cur_field; -- return; -- } -- } -- } -- } --} -- - static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) - { - struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1803,8 +1868,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) - /* Wake up the device in case it's already suspended */ - pm_runtime_get_sync(&udev->dev); - -- get_type_cover_backlight_field(hdev, &field); -- if (!field) { -+ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], -+ &field, -+ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { - hid_err(hdev, "couldn't find backlight field\n"); - goto out; - } -@@ -1941,13 +2007,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) - - static int mt_reset_resume(struct hid_device *hdev) - { -+ struct mt_device *td = hid_get_drvdata(hdev); -+ - mt_release_contacts(hdev); - mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); -+ -+ /* Request an update on the typecover folding state on resume -+ * after reset. -+ */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) -+ request_type_cover_tablet_mode_switch(hdev); -+ - return 0; - } - - static int mt_resume(struct hid_device *hdev) - { -+ struct mt_device *td = hid_get_drvdata(hdev); -+ - /* Some Elan legacy devices require SET_IDLE to be set on resume. - * It should be safe to send it to other devices too. - * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1956,12 +2033,31 @@ static int mt_resume(struct hid_device *hdev) - - mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); - -+ /* Request an update on the typecover folding state on resume. */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) -+ request_type_cover_tablet_mode_switch(hdev); -+ - return 0; - } - - static void mt_remove(struct hid_device *hdev) - { - struct mt_device *td = hid_get_drvdata(hdev); -+ struct hid_field *field; -+ struct input_dev *input; -+ -+ /* Reset tablet mode switch on disconnect. */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { -+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], -+ &field, -+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { -+ input = field->hidinput->input; -+ input_report_switch(input, SW_TABLET_MODE, 0); -+ input_sync(input); -+ } else { -+ hid_err(hdev, "couldn't find tablet mode field\n"); -+ } -+ } - - unregister_pm_notifier(&td->pm_notifier); - del_timer_sync(&td->release_timer); --- -2.47.1 - diff --git a/patches/6.14-rc4/0010-surface-shutdown.patch b/patches/6.14-rc4/0010-surface-shutdown.patch deleted file mode 100644 index 9194e85fe8..0000000000 --- a/patches/6.14-rc4/0010-surface-shutdown.patch +++ /dev/null @@ -1,97 +0,0 @@ -From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod - -Work around buggy EFI firmware: On some Microsoft Surface devices -(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with -EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the -system down, it returns and the system stays on. - -It turns out that this only happens after PCI shutdown callbacks ran for -specific devices. Excluding those devices from the shutdown process -makes the ResetSystem call work as expected. - -TODO: Maybe we can find a better way or the root cause of this? - -Not-Signed-off-by: Maximilian Luz -Patchset: surface-shutdown ---- - drivers/pci/pci-driver.c | 3 +++ - drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ - include/linux/pci.h | 1 + - 3 files changed, 40 insertions(+) - -diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 35270172c833..529779994ef6 100644 ---- a/drivers/pci/pci-driver.c -+++ b/drivers/pci/pci-driver.c -@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) - struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = pci_dev->driver; - -+ if (pci_dev->no_shutdown) -+ return; -+ - pm_runtime_resume(dev); - - if (drv && drv->shutdown) -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 8103bc24a54e..e8fa8d810925 100644 ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -6301,3 +6301,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); - #endif -+ -+static const struct dmi_system_id no_shutdown_dmi_table[] = { -+ /* -+ * Systems on which some devices should not be touched during shutdown. -+ */ -+ { -+ .ident = "Microsoft Surface Pro 9", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), -+ }, -+ }, -+ { -+ .ident = "Microsoft Surface Laptop 5", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), -+ }, -+ }, -+ {} -+}; -+ -+static void quirk_no_shutdown(struct pci_dev *dev) -+{ -+ if (!dmi_check_system(no_shutdown_dmi_table)) -+ return; -+ -+ dev->no_shutdown = 1; -+ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", -+ dev->vendor, dev->device); -+} -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU -diff --git a/include/linux/pci.h b/include/linux/pci.h -index 4e77c4230c0a..a4b0e6ef6cfe 100644 ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -467,6 +467,7 @@ struct pci_dev { - unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ - unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ - unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ -+ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; /* pci_enable_device has been called */ - --- -2.47.1 - diff --git a/patches/6.14-rc4/0011-surface-gpe.patch b/patches/6.14-rc4/0011-surface-gpe.patch deleted file mode 100644 index cb83acb03c..0000000000 --- a/patches/6.14-rc4/0011-surface-gpe.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 8120dc21068acfe547e9c6d1cced417e5931c7ad Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 12 Mar 2023 01:41:57 +0100 -Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 - -Add the lid GPE used by the Surface Pro 9. - -Signed-off-by: Maximilian Luz -Patchset: surface-gpe ---- - drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index 62fd4004db31..103fc4468262 100644 ---- a/drivers/platform/surface/surface_gpe.c -+++ b/drivers/platform/surface/surface_gpe.c -@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { - {}, - }; - -+static const struct property_entry lid_device_props_l52[] = { -+ PROPERTY_ENTRY_U32("gpe", 0x52), -+ {}, -+}; -+ - static const struct property_entry lid_device_props_l57[] = { - PROPERTY_ENTRY_U32("gpe", 0x57), - {}, -@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { - }, - .driver_data = (void *)lid_device_props_l4B, - }, -+ { -+ /* -+ * We match for SKU here due to product name clash with the ARM -+ * version. -+ */ -+ .ident = "Surface Pro 9", -+ .matches = { -+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), -+ }, -+ .driver_data = (void *)lid_device_props_l52, -+ }, - { - .ident = "Surface Book 1", - .matches = { --- -2.47.1 - diff --git a/patches/6.14-rc4/0012-cameras.patch b/patches/6.14-rc4/0012-cameras.patch deleted file mode 100644 index 64014fd030..0000000000 --- a/patches/6.14-rc4/0012-cameras.patch +++ /dev/null @@ -1,734 +0,0 @@ -From 2cb3cbe91cb78a8747e6eee341c1d4e20c459d16 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sun, 10 Oct 2021 20:56:57 +0200 -Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an - INT3472 device - -The clk and regulator frameworks expect clk/regulator consumer-devices -to have info about the consumed clks/regulators described in the device's -fw_node. - -To work around cases where this info is not present in the firmware tables, -which is often the case on x86/ACPI devices, both frameworks allow the -provider-driver to attach info about consumers to the clks/regulators -when registering these. - -This causes problems with the probe ordering wrt drivers for consumers -of these clks/regulators. Since the lookups are only registered when the -provider-driver binds, trying to get these clks/regulators before then -results in a -ENOENT error for clks and a dummy regulator for regulators. - -One case where we hit this issue is camera sensors such as e.g. the OV8865 -sensor found on the Microsoft Surface Go. The sensor uses clks, regulators -and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 -ACPI device. There is special platform code handling this and setting -platform_data with the necessary consumer info on the MFD cells -instantiated for the PMIC under: drivers/platform/x86/intel/int3472. - -For this to work properly the ov8865 driver must not bind to the I2C-client -for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and -clk MFD cells have all been fully setup. - -The OV8865 on the Microsoft Surface Go is just one example, all X86 -devices using the Intel IPU3 camera block found on recent Intel SoCs -have similar issues where there is an INT3472 HID ACPI-device, which -describes the clks and regulators, and the driver for this INT3472 device -must be fully initialized before the sensor driver (any sensor driver) -binds for things to work properly. - -On these devices the ACPI nodes describing the sensors all have a _DEP -dependency on the matching INT3472 ACPI device (there is one per sensor). - -This allows solving the probe-ordering problem by delaying the enumeration -(instantiation of the I2C-client in the ov8865 example) of ACPI-devices -which have a _DEP dependency on an INT3472 device. - -The new acpi_dev_ready_for_enumeration() helper used for this is also -exported because for devices, which have the enumeration_by_parent flag -set, the parent-driver will do its own scan of child ACPI devices and -it will try to enumerate those during its probe(). Code doing this such -as e.g. the i2c-core-acpi.c code must call this new helper to ensure -that it too delays the enumeration until all the _DEP dependencies are -met on devices which have the new honor_deps flag set. - -Signed-off-by: Hans de Goede -Patchset: cameras ---- - drivers/acpi/scan.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 7ecc401fb97f..e35185de1902 100644 ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, - - static void acpi_default_enumeration(struct acpi_device *device) - { -+ if (!acpi_dev_ready_for_enumeration(device)) -+ return; -+ - /* - * Do not enumerate devices with enumeration_by_parent flag set as - * they will be enumerated by their respective parents. --- -2.47.1 - -From 29efdd823d22e0a6f7dead43d9c309602a1d2cbd Mon Sep 17 00:00:00 2001 -From: zouxiaoh -Date: Fri, 25 Jun 2021 08:52:59 +0800 -Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs - -Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, -The IPU driver allocates its own page table that is not mapped -via the DMA, and thus the Intel IOMMU driver blocks access giving -this error: DMAR: DRHD: handling fault status reg 3 DMAR: -[DMA Read] Request device [00:05.0] PASID ffffffff -fault addr 76406000 [fault reason 06] PTE Read access is not set -As IPU is not an external facing device which is not risky, so use -IOMMU passthrough mode for Intel IPUs. - -Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b -Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 -Tracked-On: #JIITL8-411 -Signed-off-by: Bingbu Cao -Signed-off-by: zouxiaoh -Signed-off-by: Xu Chongyang -Patchset: cameras ---- - drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index c010aebe6cc1..42b342184d56 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -45,6 +45,13 @@ - ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ - ) - -+#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ -+ ((pdev)->device == 0x9a19 || \ -+ (pdev)->device == 0x9a39 || \ -+ (pdev)->device == 0x4e19 || \ -+ (pdev)->device == 0x465d || \ -+ (pdev)->device == 0x1919)) -+ - #define IOAPIC_RANGE_START (0xfee00000) - #define IOAPIC_RANGE_END (0xfeefffff) - #define IOVA_START_ADDR (0x1000) -@@ -214,12 +221,14 @@ int intel_iommu_enabled = 0; - EXPORT_SYMBOL_GPL(intel_iommu_enabled); - - static int dmar_map_ipts = 1; -+static int dmar_map_ipu = 1; - static int intel_iommu_superpage = 1; - static int iommu_identity_mapping; - static int iommu_skip_te_disable; - static int disable_igfx_iommu; - - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPU 8 - #define IDENTMAP_IPTS 16 - - const struct iommu_ops intel_iommu_ops; -@@ -2054,6 +2063,9 @@ static int device_def_domain_type(struct device *dev) - if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) - return IOMMU_DOMAIN_IDENTITY; - -+ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; -+ - if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) - return IOMMU_DOMAIN_IDENTITY; - } -@@ -2354,6 +2366,9 @@ static int __init init_dmars(void) - iommu_set_root_entry(iommu); - } - -+ if (!dmar_map_ipu) -+ iommu_identity_mapping |= IDENTMAP_IPU; -+ - if (!dmar_map_ipts) - iommu_identity_mapping |= IDENTMAP_IPTS; - -@@ -4664,6 +4679,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - disable_igfx_iommu = 1; - } - -+static void quirk_iommu_ipu(struct pci_dev *dev) -+{ -+ if (!IS_INTEL_IPU(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; -+ -+ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); -+ dmar_map_ipu = 0; -+} -+ - static void quirk_iommu_ipts(struct pci_dev *dev) - { - if (!IS_IPTS(dev)) -@@ -4711,6 +4738,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); - -+/* disable IPU dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); -+ - /* disable IPTS dmar support */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); --- -2.47.1 - -From 503ddf1a3c915d4b1108b44a280fd588fd11252c Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Sun, 10 Oct 2021 20:57:02 +0200 -Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain - -The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic -can be forwarded to a device connected to the PMIC as though it were -connected directly to the system bus. Enable this mode when the chip -is initialised. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 1e107fd49f82..e3e1696e7f0e 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) - return ret; - } - -+ /* Enable I2C daisy chain */ -+ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); -+ if (ret) { -+ dev_err(dev, "Failed to enable i2c daisy chain\n"); -+ return ret; -+ } -+ - dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); - - return 0; --- -2.47.1 - -From 46806f2df854794beb466026561dc6446ec77632 Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Thu, 2 Mar 2023 12:59:39 +0000 -Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E - -ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The -driver for this sensor expects a single pin named "enable", but on -some Microsoft Surface platforms the sensor is assigned a single -GPIO who's type flag is INT3472_GPIO_TYPE_RESET. - -Remap the GPIO pin's function from "reset" to "enable". This is done -outside of the existing remap table since it is a more widespread -discrepancy than that method is designed for. Additionally swap the -polarity of the pin to match the driver's expectation. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 3de463c3d13b..0a012eeed30a 100644 ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - const char *func, u32 polarity) - { - int ret; -+ const struct acpi_device_id ov7251_ids[] = { -+ { "INT347E" }, -+ { } -+ }; - - if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { - dev_warn(int3472->dev, "Too many GPIOs mapped\n"); - return -EINVAL; - } - -+ /* -+ * In addition to the function remap table we need to bulk remap the -+ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that -+ * expects its only GPIO pin to be called "enable" (and to have the -+ * opposite polarity). -+ */ -+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { -+ func = "enable"; -+ polarity ^= GPIO_ACTIVE_LOW; -+ } -+ - ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, func, polarity); - if (ret) --- -2.47.1 - -From af26f5acd84f8f7db95873690902562a159a94fb Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Tue, 21 Mar 2023 13:45:26 +0000 -Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 - -Update the control ID for the gain control in the ov7251 driver to -V4L2_CID_ANALOGUE_GAIN. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/media/i2c/ov7251.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf..9c1292ca8552 100644 ---- a/drivers/media/i2c/ov7251.c -+++ b/drivers/media/i2c/ov7251.c -@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) - case V4L2_CID_EXPOSURE: - ret = ov7251_set_exposure(ov7251, ctrl->val); - break; -- case V4L2_CID_GAIN: -+ case V4L2_CID_ANALOGUE_GAIN: - ret = ov7251_set_gain(ov7251, ctrl->val); - break; - case V4L2_CID_TEST_PATTERN: -@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) - ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, - V4L2_CID_EXPOSURE, 1, 32, 1, 32); - ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, -- V4L2_CID_GAIN, 16, 1023, 1, 16); -+ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); - v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, - V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(ov7251_test_pattern_menu) - 1, --- -2.47.1 - -From d0bcf0400f018b7d505f47bcf21ef7843f1372ca Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Wed, 22 Mar 2023 11:01:42 +0000 -Subject: [PATCH] media: v4l2-core: Acquire privacy led in - v4l2_async_register_subdev() - -The current call to v4l2_subdev_get_privacy_led() is contained in -v4l2_async_register_subdev_sensor(), but that function isn't used by -all the sensor drivers. Move the acquisition of the privacy led to -v4l2_async_register_subdev() instead. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/media/v4l2-core/v4l2-async.c | 4 ++++ - drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index ee884a8221fb..4f6bafd900ee 100644 ---- a/drivers/media/v4l2-core/v4l2-async.c -+++ b/drivers/media/v4l2-core/v4l2-async.c -@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) - - INIT_LIST_HEAD(&sd->asc_list); - -+ ret = v4l2_subdev_get_privacy_led(sd); -+ if (ret < 0) -+ return ret; -+ - /* - * No reference taken. The reference is held by the device (struct - * v4l2_subdev.dev), and async sub-device does not exist independently -diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index f19c8adf2c61..923ed1b5ab8b 100644 ---- a/drivers/media/v4l2-core/v4l2-fwnode.c -+++ b/drivers/media/v4l2-core/v4l2-fwnode.c -@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) - - v4l2_async_subdev_nf_init(notifier, sd); - -- ret = v4l2_subdev_get_privacy_led(sd); -- if (ret < 0) -- goto out_cleanup; -- - ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); - if (ret < 0) - goto out_cleanup; --- -2.47.1 - -From 222586440493b857e7c5aa363f8741b7fff753be Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:16 +0800 -Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED - -Add MFD cell for tps68470-led. - -Reviewed-by: Daniel Scally -Signed-off-by: Kate Hsuan -Reviewed-by: Hans de Goede -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index e3e1696e7f0e..423dc555093f 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -17,7 +17,7 @@ - #define DESIGNED_FOR_CHROMEOS 1 - #define DESIGNED_FOR_WINDOWS 2 - --#define TPS68470_WIN_MFD_CELL_COUNT 3 -+#define TPS68470_WIN_MFD_CELL_COUNT 4 - - static const struct mfd_cell tps68470_cros[] = { - { .name = "tps68470-gpio" }, -@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) - cells[1].name = "tps68470-regulator"; - cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; - cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); -- cells[2].name = "tps68470-gpio"; -+ cells[2].name = "tps68470-led"; -+ cells[3].name = "tps68470-gpio"; - - for (i = 0; i < board_data->n_gpiod_lookups; i++) - gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); --- -2.47.1 - -From b0e450741669b478b74d8610fd9dbae817962077 Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:17 +0800 -Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB - -Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB -(TPS68470_ILEDCTL_ENB), and current control mask for LEDB -(TPS68470_ILEDCTL_CTRLB) - -Reviewed-by: Daniel Scally -Reviewed-by: Hans de Goede -Signed-off-by: Kate Hsuan -Patchset: cameras ---- - include/linux/mfd/tps68470.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 ---- a/include/linux/mfd/tps68470.h -+++ b/include/linux/mfd/tps68470.h -@@ -34,6 +34,7 @@ - #define TPS68470_REG_SGPO 0x22 - #define TPS68470_REG_GPDI 0x26 - #define TPS68470_REG_GPDO 0x27 -+#define TPS68470_REG_ILEDCTL 0x28 - #define TPS68470_REG_VCMVAL 0x3C - #define TPS68470_REG_VAUX1VAL 0x3D - #define TPS68470_REG_VAUX2VAL 0x3E -@@ -94,4 +95,8 @@ - #define TPS68470_GPIO_MODE_OUT_CMOS 2 - #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 - -+#define TPS68470_ILEDCTL_ENA BIT(2) -+#define TPS68470_ILEDCTL_ENB BIT(6) -+#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) -+ - #endif /* __LINUX_MFD_TPS68470_H */ --- -2.47.1 - -From 7f546475ba781cf67aedd9817046b506873edab1 Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:18 +0800 -Subject: [PATCH] leds: tps68470: Add LED control for tps68470 - -There are two LED controllers, LEDA indicator LED and LEDB flash LED for -tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, -tps68470 provides four levels of power status for LEDB. If the -properties called "ti,ledb-current" can be found, the current will be -set according to the property values. These two LEDs can be controlled -through the LED class of sysfs (tps68470-leda and tps68470-ledb). - -Signed-off-by: Kate Hsuan -Reviewed-by: Hans de Goede -Patchset: cameras ---- - drivers/leds/Kconfig | 12 +++ - drivers/leds/Makefile | 1 + - drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ - 3 files changed, 198 insertions(+) - create mode 100644 drivers/leds/leds-tps68470.c - -diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index b784bb74a837..f8d8fcfacac2 100644 ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -941,6 +941,18 @@ config LEDS_TPS6105X - It is a single boost converter primarily for white LEDs and - audio amplifiers. - -+config LEDS_TPS68470 -+ tristate "LED support for TI TPS68470" -+ depends on LEDS_CLASS -+ depends on INTEL_SKL_INT3472 -+ help -+ This driver supports TPS68470 PMIC with LED chip. -+ It provides two LED controllers, with the ability to drive 2 -+ indicator LEDs and 2 flash LEDs. -+ -+ To compile this driver as a module, choose M and it will be -+ called leds-tps68470 -+ - config LEDS_IP30 - tristate "LED support for SGI Octane machines" - depends on LEDS_CLASS -diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 18afbb5a23ee..a1d16c0af82d 100644 ---- a/drivers/leds/Makefile -+++ b/drivers/leds/Makefile -@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o - obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o - obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o - obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o -+obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o - obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o - obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o - obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o -diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c -new file mode 100644 -index 000000000000..35aeb5db89c8 ---- /dev/null -+++ b/drivers/leds/leds-tps68470.c -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * LED driver for TPS68470 PMIC -+ * -+ * Copyright (C) 2023 Red Hat -+ * -+ * Authors: -+ * Kate Hsuan -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define lcdev_to_led(led_cdev) \ -+ container_of(led_cdev, struct tps68470_led, lcdev) -+ -+#define led_to_tps68470(led, index) \ -+ container_of(led, struct tps68470_device, leds[index]) -+ -+enum tps68470_led_ids { -+ TPS68470_ILED_A, -+ TPS68470_ILED_B, -+ TPS68470_NUM_LEDS -+}; -+ -+static const char *tps68470_led_names[] = { -+ [TPS68470_ILED_A] = "tps68470-iled_a", -+ [TPS68470_ILED_B] = "tps68470-iled_b", -+}; -+ -+struct tps68470_led { -+ unsigned int led_id; -+ struct led_classdev lcdev; -+}; -+ -+struct tps68470_device { -+ struct device *dev; -+ struct regmap *regmap; -+ struct tps68470_led leds[TPS68470_NUM_LEDS]; -+}; -+ -+enum ctrlb_current { -+ CTRLB_2MA = 0, -+ CTRLB_4MA = 1, -+ CTRLB_8MA = 2, -+ CTRLB_16MA = 3, -+}; -+ -+static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) -+{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, -+ brightness ? TPS68470_ILEDCTL_ENA : 0); -+ case TPS68470_ILED_B: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, -+ brightness ? TPS68470_ILEDCTL_ENB : 0); -+ } -+ return -EINVAL; -+} -+ -+static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) -+{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ int ret = 0; -+ int value = 0; -+ -+ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); -+ if (ret) -+ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); -+ -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ value = value & TPS68470_ILEDCTL_ENA; -+ break; -+ case TPS68470_ILED_B: -+ value = value & TPS68470_ILEDCTL_ENB; -+ break; -+ } -+ -+ return value ? LED_ON : LED_OFF; -+} -+ -+ -+static int tps68470_ledb_current_init(struct platform_device *pdev, -+ struct tps68470_device *tps68470) -+{ -+ int ret = 0; -+ unsigned int curr; -+ -+ /* configure LEDB current if the properties can be got */ -+ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { -+ if (curr > CTRLB_16MA) { -+ dev_err(&pdev->dev, -+ "Invalid LEDB current value: %d\n", -+ curr); -+ return -EINVAL; -+ } -+ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, -+ TPS68470_ILEDCTL_CTRLB, curr); -+ } -+ return ret; -+} -+ -+static int tps68470_leds_probe(struct platform_device *pdev) -+{ -+ int i = 0; -+ int ret = 0; -+ struct tps68470_device *tps68470; -+ struct tps68470_led *led; -+ struct led_classdev *lcdev; -+ -+ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), -+ GFP_KERNEL); -+ if (!tps68470) -+ return -ENOMEM; -+ -+ tps68470->dev = &pdev->dev; -+ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); -+ -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ led = &tps68470->leds[i]; -+ lcdev = &led->lcdev; -+ -+ led->led_id = i; -+ -+ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", -+ tps68470_led_names[i], LED_FUNCTION_INDICATOR); -+ if (!lcdev->name) -+ return -ENOMEM; -+ -+ lcdev->max_brightness = 1; -+ lcdev->brightness = 0; -+ lcdev->brightness_set_blocking = tps68470_brightness_set; -+ lcdev->brightness_get = tps68470_brightness_get; -+ lcdev->dev = &pdev->dev; -+ -+ ret = devm_led_classdev_register(tps68470->dev, lcdev); -+ if (ret) { -+ dev_err_probe(tps68470->dev, ret, -+ "error registering led\n"); -+ goto err_exit; -+ } -+ -+ if (i == TPS68470_ILED_B) { -+ ret = tps68470_ledb_current_init(pdev, tps68470); -+ if (ret) -+ goto err_exit; -+ } -+ } -+ -+err_exit: -+ if (ret) { -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ if (tps68470->leds[i].lcdev.name) -+ devm_led_classdev_unregister(&pdev->dev, -+ &tps68470->leds[i].lcdev); -+ } -+ } -+ -+ return ret; -+} -+static struct platform_driver tps68470_led_driver = { -+ .driver = { -+ .name = "tps68470-led", -+ }, -+ .probe = tps68470_leds_probe, -+}; -+ -+module_platform_driver(tps68470_led_driver); -+ -+MODULE_ALIAS("platform:tps68470-led"); -+MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); -+MODULE_LICENSE("GPL v2"); --- -2.47.1 - -From adf794d65cca167d5bc66ef0c8a160e3fbeb3481 Mon Sep 17 00:00:00 2001 -From: mojyack -Date: Tue, 26 Mar 2024 05:55:44 +0900 -Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 - -On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". -The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. -So just add some delay. -There is no exact reason for this 10000us, but 100us failed. - -Patchset: cameras ---- - drivers/media/i2c/dw9719.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..0094cfda57ea 100644 ---- a/drivers/media/i2c/dw9719.c -+++ b/drivers/media/i2c/dw9719.c -@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) - if (ret) - return ret; - -+ /* Wait for device to be acknowledged */ -+ fsleep(10000); -+ - /* Jiggle SCL pin to wake up device */ - cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); - --- -2.47.1 - diff --git a/patches/6.14-rc4/0013-amd-gpio.patch b/patches/6.14-rc4/0013-amd-gpio.patch deleted file mode 100644 index 93c8956a23..0000000000 --- a/patches/6.14-rc4/0013-amd-gpio.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 28b8120e4f9b02ec49ccedd036557552a1aee5dc Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Sat, 29 May 2021 17:47:38 +1000 -Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 - override - -This patch is the work of Thomas Gleixner and is -copied from: -https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ - -This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin -setup that is missing in the laptops ACPI table. - -This patch was used for validation of the issue, and is not a proper -fix, but is probably a better temporary hack than continuing to probe -the Legacy PIC and run with the PIC in an unknown state. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 4efecac49863..88377bb0d137 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) - } - } - -+static const struct dmi_system_id surface_quirk[] __initconst = { -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") -+ }, -+ }, -+ {} -+}; -+ - /* - * Parse IOAPIC related entries in MADT - * returns 0 on success, < 0 on error -@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) - acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, - acpi_gbl_FADT.sci_interrupt); - -+ if (dmi_check_system(surface_quirk)) { -+ pr_warn("Surface hack: Override irq 7\n"); -+ mp_override_legacy_irq(7, 3, 3, 7); -+ } -+ - /* Fill in identity legacy mappings where no override */ - mp_config_acpi_legacy_irqs(); - --- -2.47.1 - -From 1b801d759aced457e5508cf931fa849400233b92 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Thu, 3 Jun 2021 14:04:26 +0200 -Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override - quirk - -The 13" version of the Surface Laptop 4 has the same problem as the 15" -version, but uses a different SKU. Add that SKU to the quirk as well. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 88377bb0d137..c58f26918b17 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) - - static const struct dmi_system_id surface_quirk[] __initconst = { - { -- .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") - }, - }, -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") -+ }, -+ }, - {} - }; - --- -2.47.1 - diff --git a/patches/6.14-rc4/0014-rtc.patch b/patches/6.14-rc4/0014-rtc.patch deleted file mode 100644 index 784921d06d..0000000000 --- a/patches/6.14-rc4/0014-rtc.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 0a6b868f61d7564bc898ac30c84fbf3c34fb7368 Mon Sep 17 00:00:00 2001 -From: "Bart Groeneveld | GPX Solutions B.V" -Date: Mon, 5 Dec 2022 16:08:46 +0100 -Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms - -The specification [1] allows so-called HW-reduced platforms, -which do not implement everything, especially the wakeup related stuff. - -In that case, it is still usable as a RTC. This is helpful for [2] -and [3], which is about a device with no other working RTC, -but it does have an HW-reduced TAD, which can be used as a RTC instead. - -[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device -[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 -[3]: https://github.com/linux-surface/linux-surface/issues/415 - -Signed-off-by: Bart Groeneveld | GPX Solutions B.V. -Patchset: rtc ---- - drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ - 1 file changed, 24 insertions(+), 12 deletions(-) - -diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index b831cb8e53dc..78bd0f926505 100644 ---- a/drivers/acpi/acpi_tad.c -+++ b/drivers/acpi/acpi_tad.c -@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RO(caps); - -+static struct attribute *acpi_tad_attrs[] = { -+ &dev_attr_caps.attr, -+ NULL, -+}; -+static const struct attribute_group acpi_tad_attr_group = { -+ .attrs = acpi_tad_attrs, -+}; -+ - static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) - { -@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RW(ac_status); - --static struct attribute *acpi_tad_attrs[] = { -- &dev_attr_caps.attr, -+static struct attribute *acpi_tad_ac_attrs[] = { - &dev_attr_ac_alarm.attr, - &dev_attr_ac_policy.attr, - &dev_attr_ac_status.attr, - NULL, - }; --static const struct attribute_group acpi_tad_attr_group = { -- .attrs = acpi_tad_attrs, -+static const struct attribute_group acpi_tad_ac_attr_group = { -+ .attrs = acpi_tad_ac_attrs, - }; - - static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, -@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) - - pm_runtime_get_sync(dev); - -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) -+ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ - if (dd->capabilities & ACPI_TAD_DC_WAKE) - sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); - - sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); - -- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) { -+ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -+ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ } - if (dd->capabilities & ACPI_TAD_DC_WAKE) { - acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); - acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); -@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) - goto remove_handler; - } - -- if (!acpi_has_method(handle, "_PRW")) { -- dev_info(dev, "Missing _PRW\n"); -- ret = -ENODEV; -- goto remove_handler; -- } -- - dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); - if (!dd) { - ret = -ENOMEM; -@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) - if (ret) - goto fail; - -+ if (caps & ACPI_TAD_AC_WAKE) { -+ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ if (ret) -+ goto fail; -+ } -+ - if (caps & ACPI_TAD_DC_WAKE) { - ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); - if (ret) --- -2.47.1 - From d02ca901f713178d46af77dad164ed9d4febc1e4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 02:34:22 +0200 Subject: [PATCH 097/236] Update v6.14 patches Changes: - Add basic SAM support for Surface Laptop 7 (Intel) - Rebase onto v6.14.2 Links: - kernel: https://github.com/linux-surface/kernel/commit/15bf9fcbacae64d8a208be07828b4aa7ae031482 --- patches/6.14/0001-secureboot.patch | 18 +- patches/6.14/0002-surface3-oemb.patch | 101 --- patches/6.14/0002-surface3.patch | 234 ++++++ patches/6.14/0003-mwifiex.patch | 20 +- patches/6.14/0004-ath10k.patch | 4 +- patches/6.14/0005-ipts.patch | 48 +- patches/6.14/0006-ithc.patch | 34 +- patches/6.14/0007-surface-sam.patch | 211 +++++ ....patch => 0008-surface-sam-over-hid.patch} | 14 +- ...button.patch => 0009-surface-button.patch} | 10 +- ...ver.patch => 0010-surface-typecover.patch} | 70 +- ...down.patch => 0011-surface-shutdown.patch} | 31 +- ...rface-gpe.patch => 0012-surface-gpe.patch} | 6 +- patches/6.14/0013-cameras.patch | 734 ++++++++++++++++++ ...013-amd-gpio.patch => 0014-amd-gpio.patch} | 18 +- .../6.14/{0014-rtc.patch => 0015-rtc.patch} | 6 +- 16 files changed, 1306 insertions(+), 253 deletions(-) delete mode 100644 patches/6.14/0002-surface3-oemb.patch create mode 100644 patches/6.14/0002-surface3.patch create mode 100644 patches/6.14/0007-surface-sam.patch rename patches/6.14/{0007-surface-sam-over-hid.patch => 0008-surface-sam-over-hid.patch} (96%) rename patches/6.14/{0008-surface-button.patch => 0009-surface-button.patch} (96%) rename patches/6.14/{0009-surface-typecover.patch => 0010-surface-typecover.patch} (90%) rename patches/6.14/{0010-surface-shutdown.patch => 0011-surface-shutdown.patch} (74%) rename patches/6.14/{0011-surface-gpe.patch => 0012-surface-gpe.patch} (92%) create mode 100644 patches/6.14/0013-cameras.patch rename patches/6.14/{0013-amd-gpio.patch => 0014-amd-gpio.patch} (87%) rename patches/6.14/{0014-rtc.patch => 0015-rtc.patch} (96%) diff --git a/patches/6.14/0001-secureboot.patch b/patches/6.14/0001-secureboot.patch index addb86e813..a850f2286e 100644 --- a/patches/6.14/0001-secureboot.patch +++ b/patches/6.14/0001-secureboot.patch @@ -1,4 +1,4 @@ -From bbcfb18eb05bd92e4501ca35bdfd558c849ddeda Mon Sep 17 00:00:00 2001 +From 021ec07abb3238472d89815c934fb3dc07f1b29e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.47.1 +2.49.0 -From 9a796344897d077f1fc977ab026315c2cfcd3960 Mon Sep 17 00:00:00 2001 +From 4c1408f0a6a9ee5b1998253f4f30c04eb1e96240 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,10 +53,10 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index d401577b5a6a..5a812e0b740a 100644 +index fb8752b42ec8..d46bb052b3a1 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3066,6 +3066,11 @@ +@@ -3154,6 +3154,11 @@ to extract confidential information from the kernel are also disabled. @@ -69,7 +69,7 @@ index d401577b5a6a..5a812e0b740a 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index e35829d36039..6d54eb03b63d 100644 +index 10a01af63a80..e53e4a86e4cc 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -37,6 +37,7 @@ @@ -89,7 +89,7 @@ index e35829d36039..6d54eb03b63d 100644 !secretmem_active() && !cxl_mem_active(); } -@@ -1426,6 +1427,12 @@ static int __init nohibernate_setup(char *str) +@@ -1434,6 +1435,12 @@ static int __init nohibernate_setup(char *str) return 1; } @@ -102,11 +102,11 @@ index e35829d36039..6d54eb03b63d 100644 static const char * const comp_alg_enabled[] = { #if IS_ENABLED(CONFIG_CRYPTO_LZO) COMPRESSION_ALGO_LZO, -@@ -1484,3 +1491,4 @@ __setup("hibernate=", hibernate_setup); +@@ -1492,3 +1499,4 @@ __setup("hibernate=", hibernate_setup); __setup("resumewait", resumewait_setup); __setup("resumedelay=", resumedelay_setup); __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0002-surface3-oemb.patch b/patches/6.14/0002-surface3-oemb.patch deleted file mode 100644 index ab40dd606c..0000000000 --- a/patches/6.14/0002-surface3-oemb.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 2ce5cf2a597c9015c64ea9f386a396f97b8589c6 Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 18 Oct 2020 16:42:44 +0900 -Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI - table - -On some Surface 3, the DMI table gets corrupted for unknown reasons -and breaks existing DMI matching used for device-specific quirks. - -This commit adds the (broken) DMI data into dmi_system_id tables used -for quirks so that each driver can enable quirks even on the affected -systems. - -On affected systems, DMI data will look like this: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:OEMB - /sys/devices/virtual/dmi/id/board_vendor:OEMB - /sys/devices/virtual/dmi/id/chassis_vendor:OEMB - /sys/devices/virtual/dmi/id/product_name:OEMB - /sys/devices/virtual/dmi/id/sys_vendor:OEMB - -Expected: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:Surface 3 - /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/product_name:Surface 3 - /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation - -Signed-off-by: Tsuchiya Yuto -Patchset: surface3-oemb ---- - drivers/platform/surface/surface3-wmi.c | 7 +++++++ - sound/soc/codecs/rt5645.c | 9 +++++++++ - sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ - 3 files changed, 24 insertions(+) - -diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index c15ed7a12784..1ec8edb5aafa 100644 ---- a/drivers/platform/surface/surface3-wmi.c -+++ b/drivers/platform/surface/surface3-wmi.c -@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - #endif - { } - }; -diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 51187b1e0ed2..bfb83ce8d8f8 100644 ---- a/sound/soc/codecs/rt5645.c -+++ b/sound/soc/codecs/rt5645.c -@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { - }, - .driver_data = (void *)&intel_braswell_platform_data, - }, -+ { -+ .ident = "Microsoft Surface 3", -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ .driver_data = (void *)&intel_braswell_platform_data, -+ }, - { - /* - * Match for the GPDwin which unfortunately uses somewhat -diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0c28..0b930c91bccb 100644 ---- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .callback = cht_surface_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - { } - }; - --- -2.47.1 - diff --git a/patches/6.14/0002-surface3.patch b/patches/6.14/0002-surface3.patch new file mode 100644 index 0000000000..b45cfd8644 --- /dev/null +++ b/patches/6.14/0002-surface3.patch @@ -0,0 +1,234 @@ +From 97e443f4ec202c66165990d72c05aa28c359b31e Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3 +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index 6c8fb7a4dde4..22797a53f4d8 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.49.0 + +From ebacd5e19eb63db32a538bab0d9e5b44737a24bb Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Fri, 6 Dec 2019 23:10:30 +0900 +Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by + default + +On Arch Linux kernel at least after 4.19, touch input is broken after suspend +(s2idle). + + kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + +On recent stable Arch Linux kernel (at least after 5.1), touch input will +crash after the first touch. + + kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue + +I found on an affected system (Arch Linux kernel, etc.), the touchscreen +driver uses DMA mode by default. Then, we found some kernels with different +kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel +chromeos-4.19 [2]) will use PIO mode by default and no such issues there. + +So, this commit disables DMA mode on the touchscreen driver side as a quick +workaround to avoid touch input crash. +We may need to properly set up DMA mode to use the touchscreen driver with +DMA mode. + +You can still switch DMA/PIO mode if you want: + + switch to DMA mode (maybe broken) + echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma + back to PIO mode + echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma + +Link to issue: https://github.com/jakeday/linux-surface/issues/596 + +References: +[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config +[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 + +Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. +This commit made the driver use PIO by default and no touch input crash. +Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default +even without this commit. After this commit, it still uses PIO and confirmed +no functional changes regarding touch input. + +More details: + We can confirm which mode the touchscreen driver uses; first, enable + debug output: + + echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + + Then, try to make a touch input and see dmesg log + + (On Arch Linux kernel, uses DMA) + kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA + kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 + c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + + (On the kernels I referenced above, uses PIO) + kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO + kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 + 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Note (2025-03-08): This patch was originally dropped due to the +comments in [3]. However, according to the commments in [4] it is still +required. + +[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a +[4]: https://github.com/linux-surface/linux-surface/issues/1184 + +Patchset: surface3 +--- + drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c +index 6074b7730e86..6aa3e1d6f160 100644 +--- a/drivers/input/touchscreen/surface3_spi.c ++++ b/drivers/input/touchscreen/surface3_spi.c +@@ -25,6 +25,12 @@ + #define SURFACE3_REPORT_TOUCH 0xd2 + #define SURFACE3_REPORT_PEN 0x16 + ++bool use_dma = false; ++module_param(use_dma, bool, 0644); ++MODULE_PARM_DESC(use_dma, ++ "Disable DMA mode if you encounter touch input crash. " ++ "(default: false, disabled to avoid crash)"); ++ + struct surface3_ts_data { + struct spi_device *spi; + struct gpio_desc *gpiod_rst[2]; +@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) + return 0; + } + ++static bool surface3_spi_can_dma(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) ++{ ++ return use_dma; ++} ++ + static int surface3_spi_probe(struct spi_device *spi) + { + struct surface3_ts_data *data; +@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) + if (error) + return error; + ++ /* ++ * Set up DMA ++ * ++ * TODO: Currently, touch input with DMA seems to be broken. ++ * On 4.19 LTS, touch input will crash after suspend. ++ * On recent stable kernel (at least after 5.1), touch input will crash after ++ * the first touch. No problem with PIO on those kernels. ++ * Maybe we need to configure DMA here. ++ * ++ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 ++ */ ++ spi->controller->can_dma = surface3_spi_can_dma; ++ + return 0; + } + +-- +2.49.0 + diff --git a/patches/6.14/0003-mwifiex.patch b/patches/6.14/0003-mwifiex.patch index 523a943588..3143915c46 100644 --- a/patches/6.14/0003-mwifiex.patch +++ b/patches/6.14/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From ed54461506b98c1bc8ae8dc5f7385de1f900ed0b Mon Sep 17 00:00:00 2001 +From fd57091b497bdd3467f99e6d79d3d7319b65938f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.47.1 +2.49.0 -From a93a869673e056cf2a2c46b9438edaca8f5e2645 Mon Sep 17 00:00:00 2001 +From 9d16ab5d6b0253b5e5d28adab637ac0405052124 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.47.1 +2.49.0 -From bcc616a02ed2a9e059d2e7a1dd5b5289412efcbb Mon Sep 17 00:00:00 2001 +From f44651e18ec650050bb04a1134209da6109a8232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,10 +356,10 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 11755cb1eb16..e69c6c9957a2 100644 +index 699ff21d9767..3568d5d4906e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c -@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; +@@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) #define BTUSB_ACTIONS_SEMI BIT(27) @@ -367,7 +367,7 @@ index 11755cb1eb16..e69c6c9957a2 100644 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ -@@ -432,6 +433,7 @@ static const struct usb_device_id quirks_table[] = { +@@ -441,6 +442,7 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, @@ -375,7 +375,7 @@ index 11755cb1eb16..e69c6c9957a2 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3837,6 +3839,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3931,6 +3933,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 11755cb1eb16..e69c6c9957a2 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0004-ath10k.patch b/patches/6.14/0004-ath10k.patch index e1e6253a8b..e50e6c5b27 100644 --- a/patches/6.14/0004-ath10k.patch +++ b/patches/6.14/0004-ath10k.patch @@ -1,4 +1,4 @@ -From cc9a74a369def421de56b0581f6131c4cd15355d Mon Sep 17 00:00:00 2001 +From bb582f0942d5b505c0c2744c5a24e1711ae9ce8f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index b3294287bce1..2936fdae823c 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0005-ipts.patch b/patches/6.14/0005-ipts.patch index 9118fbc16a..7519047a5e 100644 --- a/patches/6.14/0005-ipts.patch +++ b/patches/6.14/0005-ipts.patch @@ -1,4 +1,4 @@ -From 3e89507b8f6c6d36e5bf587a74c65be5d9796ffd Mon Sep 17 00:00:00 2001 +From b89f20bfa13868323f9875acfe07e9d8f618329f Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index c3a6657dcd4a..82eef2f4eb0a 100644 +index a5f88ec97df7..e379dc2373b5 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index c3a6657dcd4a..82eef2f4eb0a 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 6589635f8ba3..a1df48a434e2 100644 +index d6ff9d82ae94..a1b714505f43 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.47.1 +2.49.0 -From 1d6df5a556693e735cc78a603c29112a76ee883b Mon Sep 17 00:00:00 2001 +From 8690c582cf49e817cff1f4ff216c4c1828682c78 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,10 +61,10 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index cc23cfcdeb2d..c010aebe6cc1 100644 +index 25d31f8c129a..3735ed60032d 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c -@@ -40,6 +40,11 @@ +@@ -39,6 +39,11 @@ #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) @@ -76,7 +76,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 #define IOAPIC_RANGE_START (0xfee00000) #define IOAPIC_RANGE_END (0xfeefffff) #define IOVA_START_ADDR (0x1000) -@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); +@@ -207,12 +212,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); int intel_iommu_enabled = 0; EXPORT_SYMBOL_GPL(intel_iommu_enabled); @@ -91,7 +91,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -2046,6 +2053,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1902,6 +1909,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 } return 0; -@@ -2344,6 +2354,9 @@ static int __init init_dmars(void) +@@ -2196,6 +2206,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 check_tylersburg_isoch(); /* -@@ -4651,6 +4664,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4493,6 +4506,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4686,6 +4711,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4528,6 +4553,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 { if (risky_device(dev)) -- -2.47.1 +2.49.0 -From e4e616d49f7a021b83cd0114f0642090e88a054f Mon Sep 17 00:00:00 2001 +From 458d45bfbecaad616ed515d82abe8598fe8c2b0e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,31 +211,23 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index f8a56d631242..38eb29e4cc31 100644 +index dfc245867a46..f91ba8a06cfc 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1386,12 +1386,14 @@ source "drivers/hid/amd-sfh-hid/Kconfig" - - source "drivers/hid/surface-hid/Kconfig" +@@ -1387,6 +1387,8 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/intel-thc-hid/Kconfig" +source "drivers/hid/ipts/Kconfig" + endif # HID - + # USB support may be used with HID disabled - - source "drivers/hid/usbhid/Kconfig" - - endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 496dab54c73a..02588e5d01eb 100644 +index 0abfe51704a0..c86c9e80d225 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -171,5 +171,7 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ - obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - +@@ -172,3 +172,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ @@ -3247,5 +3239,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0006-ithc.patch b/patches/6.14/0006-ithc.patch index 3191f6384a..f3e96a5669 100644 --- a/patches/6.14/0006-ithc.patch +++ b/patches/6.14/0006-ithc.patch @@ -1,4 +1,4 @@ -From d07e07e448b9b1ac7102911263626b623f138a28 Mon Sep 17 00:00:00 2001 +From 85f3a4111005d23749f1a5b0424264ba38bbb3f4 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,10 +10,10 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 7a6d188e3bea..0179baee4596 100644 +index ad795c772f21..2c10bca9e06b 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c -@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) +@@ -388,6 +388,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) data.busmatch_count = 0; pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); @@ -37,9 +37,9 @@ index 7a6d188e3bea..0179baee4596 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.47.1 +2.49.0 -From 280c63dff160b59d1cbac71a63dc7f16d335fec9 Mon Sep 17 00:00:00 2001 +From 3e386a2ed36c9d620f4de23d671daa75a509d797 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,36 +86,26 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 38eb29e4cc31..76ad7d9143c7 100644 +index f91ba8a06cfc..e945736e216f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1375,12 +1375,14 @@ source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/intel-thc-hid/Kconfig" +@@ -1389,6 +1389,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" source "drivers/hid/ipts/Kconfig" +source "drivers/hid/ithc/Kconfig" + endif # HID - + # USB support may be used with HID disabled - - source "drivers/hid/usbhid/Kconfig" - - endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 02588e5d01eb..1ea3d2e0d4e9 100644 +index c86c9e80d225..046eb5fd8017 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -173,6 +173,8 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - +@@ -174,3 +174,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ - + obj-$(CONFIG_HID_IPTS) += ipts/ -+ +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 @@ -2779,5 +2769,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0007-surface-sam.patch b/patches/6.14/0007-surface-sam.patch new file mode 100644 index 0000000000..a4d7a23739 --- /dev/null +++ b/patches/6.14/0007-surface-sam.patch @@ -0,0 +1,211 @@ +From 156b853c039f830407bea29f01bb6f3489c7c3e1 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 17 Jun 2022 02:14:00 +0200 +Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator + Module + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/rtc/Kconfig | 7 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 drivers/rtc/rtc-surface.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 0bbbf778ecfa..bd1d5c0dd6df 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1383,6 +1383,13 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_SURFACE ++ tristate "Microsoft Surface Aggregator RTC" ++ depends on SURFACE_AGGREGATOR ++ depends on SURFACE_AGGREGATOR_BUS ++ help ++ TODO ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 489b4ab07068..061afa9db5b6 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -180,6 +180,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o + obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o + obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o + obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o ++obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o +diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c +new file mode 100644 +index 000000000000..f6c17c4e98d5 +--- /dev/null ++++ b/drivers/rtc/rtc-surface.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * AC driver for 7th-generation Microsoft Surface devices via Surface System ++ * Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2019-2021 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct surface_rtc { ++ struct ssam_device *sdev; ++ struct rtc_device *rtc; ++}; ++ ++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x10, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x0f, ++}); ++ ++static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) ++{ ++ __le32 time_le; ++ int status; ++ ++ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); ++ if (status) ++ return status; ++ ++ *time = le32_to_cpu(time_le); ++ return 0; ++} ++ ++static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) ++{ ++ __le32 time_le = cpu_to_le32(time); ++ ++ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); ++} ++ ++static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ int status; ++ u32 time; ++ ++ status = ssam_rtc_get_unix_time(srtc, &time); ++ if (status) ++ return status; ++ ++ rtc_time64_to_tm(time, tm); ++ return 0; ++} ++ ++static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ time64_t time = rtc_tm_to_time64(tm); ++ ++ return ssam_rtc_set_unix_time(srtc, (u32)time); ++} ++ ++static const struct rtc_class_ops surface_rtc_ops = { ++ .read_time = surface_rtc_read_time, ++ .set_time = surface_rtc_set_time, ++}; ++ ++static int surface_rtc_probe(struct ssam_device *sdev) ++{ ++ struct surface_rtc *srtc; ++ ++ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->sdev = sdev; ++ ++ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); ++ if (IS_ERR(srtc->rtc)) ++ return PTR_ERR(srtc->rtc); ++ ++ srtc->rtc->ops = &surface_rtc_ops; ++ srtc->rtc->range_max = U32_MAX; ++ ++ ssam_device_set_drvdata(sdev, srtc); ++ ++ return devm_rtc_register_device(srtc->rtc); ++} ++ ++static void surface_rtc_remove(struct ssam_device *sdev) ++{ ++ /* Device-managed allocations take care of everything... */ ++} ++ ++static const struct ssam_device_id surface_rtc_match[] = { ++ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, surface_rtc_match); ++ ++static struct ssam_device_driver surface_rtc_driver = { ++ .probe = surface_rtc_probe, ++ .remove = surface_rtc_remove, ++ .match_table = surface_rtc_match, ++ .driver = { ++ .name = "surface_rtc", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(surface_rtc_driver); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.49.0 + +From 3dec366702ebcfb04f7805144eca4c943d19802b Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 20 Apr 2025 01:05:14 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 + (ACPI) + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index a594d5fcfcfd..07b03aa4fa7f 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Laptop 6 */ + { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + ++ /* Surface Laptop 7 */ ++ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.49.0 + diff --git a/patches/6.14/0007-surface-sam-over-hid.patch b/patches/6.14/0008-surface-sam-over-hid.patch similarity index 96% rename from patches/6.14/0007-surface-sam-over-hid.patch rename to patches/6.14/0008-surface-sam-over-hid.patch index a65acd8e4f..293932558f 100644 --- a/patches/6.14/0007-surface-sam-over-hid.patch +++ b/patches/6.14/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 064893f3e33bd77cecece7ea4047b3a6e1147fe2 Mon Sep 17 00:00:00 2001 +From b0c24f19804345b57672cf54e5caa7ba473f3f26 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,10 +55,10 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index 14ae0cfc325e..6197c5252d2a 100644 +index d2499f302b50..77ce5ec3dd9e 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c -@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, +@@ -661,6 +661,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, return (ret == 1) ? 0 : -EIO; } @@ -86,7 +86,7 @@ index 14ae0cfc325e..6197c5252d2a 100644 static acpi_status i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, -@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, +@@ -762,6 +783,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, } break; @@ -107,9 +107,9 @@ index 14ae0cfc325e..6197c5252d2a 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.47.1 +2.49.0 -From f6714cb9a95aeec3379336df70e7cc8d9537f727 Mon Sep 17 00:00:00 2001 +From b27002518a3b386bc3c2d50d7e45c94148375aa4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0008-surface-button.patch b/patches/6.14/0009-surface-button.patch similarity index 96% rename from patches/6.14/0008-surface-button.patch rename to patches/6.14/0009-surface-button.patch index 934e9156d2..c0676281f3 100644 --- a/patches/6.14/0008-surface-button.patch +++ b/patches/6.14/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 9d06bf6cc92b13c9e4c4781484b82804c4150d80 Mon Sep 17 00:00:00 2001 +From 3e79d7b95f28bfcd981ca7db961407b2375307be Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -20,7 +20,7 @@ Patchset: surface-button 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index 5c5d407fe965..4e1bfe90e730 100644 +index b8cad415c62c..43b5d56383e3 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -73,9 +73,9 @@ index 5c5d407fe965..4e1bfe90e730 100644 /* -- -2.47.1 +2.49.0 -From f870bb021693abb7ea617c323216c615151b62e1 Mon Sep 17 00:00:00 2001 +From 8cbc63032afb8606805a14cc1c5f29d9105567c0 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0009-surface-typecover.patch b/patches/6.14/0010-surface-typecover.patch similarity index 90% rename from patches/6.14/0009-surface-typecover.patch rename to patches/6.14/0010-surface-typecover.patch index 7cc1b3eb95..233dd01264 100644 --- a/patches/6.14/0009-surface-typecover.patch +++ b/patches/6.14/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From df8f9981df6f0a92100266397ded155314efc7e3 Mon Sep 17 00:00:00 2001 +From 79ab84535e4dd94a0ccf8159a52675f24eaca7a2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 13171454f959..a83beefd25f3 100644 +index 8efbacc5bc34..4dfb3e3023af 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index 13171454f959..a83beefd25f3 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.47.1 +2.49.0 -From 3aa9fc5fd7faed0bd5948e80e6ef6173c32a83ca Mon Sep 17 00:00:00 2001 +From 76accddaf1b7b28acb671305efb2a71eee0ea4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,10 +75,10 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e936019d21fe..08fee06fb5fc 100644 +index e50887a6d22c..4ce18f21a141 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -34,7 +34,10 @@ +@@ -35,7 +35,10 @@ #include #include #include @@ -89,7 +89,7 @@ index e936019d21fe..08fee06fb5fc 100644 #include #include #include -@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); +@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); MODULE_LICENSE("GPL"); #include "hid-ids.h" @@ -97,7 +97,7 @@ index e936019d21fe..08fee06fb5fc 100644 /* quirks to control the device */ #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) -@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); +@@ -73,12 +77,15 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) #define MT_QUIRK_DISABLE_WAKEUP BIT(21) #define MT_QUIRK_ORIENTATION_INVERT BIT(22) @@ -113,7 +113,7 @@ index e936019d21fe..08fee06fb5fc 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -168,6 +175,8 @@ struct mt_device { +@@ -176,6 +183,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -122,7 +122,7 @@ index e936019d21fe..08fee06fb5fc 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); +@@ -220,6 +229,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_GOOGLE 0x0111 #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 #define MT_CLS_SMART_TECH 0x0113 @@ -130,7 +130,7 @@ index e936019d21fe..08fee06fb5fc 100644 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -402,6 +412,16 @@ static const struct mt_class mt_classes[] = { +@@ -410,6 +420,16 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, }, @@ -147,7 +147,7 @@ index e936019d21fe..08fee06fb5fc 100644 { } }; -@@ -1751,6 +1771,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1759,6 +1779,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index e936019d21fe..08fee06fb5fc 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1774,6 +1857,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1782,6 +1865,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index e936019d21fe..08fee06fb5fc 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1812,8 +1898,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1820,8 +1906,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index e936019d21fe..08fee06fb5fc 100644 if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1822,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1830,8 +1918,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index e936019d21fe..08fee06fb5fc 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1873,6 +1963,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1881,6 +1971,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index e936019d21fe..08fee06fb5fc 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2299,6 +2390,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2304,6 +2395,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -272,9 +272,9 @@ index e936019d21fe..08fee06fb5fc 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.47.1 +2.49.0 -From c88ebc0ed1f21ec7ad52aa4fb2c48226603d7596 Mon Sep 17 00:00:00 2001 +From a10308974d385d1b666dd93ef16c5597c872199c Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,10 +303,10 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 08fee06fb5fc..f6664049f46d 100644 +index 4ce18f21a141..f5e4d52bd2eb 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); +@@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_DISABLE_WAKEUP BIT(21) #define MT_QUIRK_ORIENTATION_INVERT BIT(22) #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) @@ -314,7 +314,7 @@ index 08fee06fb5fc..f6664049f46d 100644 #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); +@@ -85,6 +86,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_CLICKPAD 0 #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 @@ -323,7 +323,7 @@ index 08fee06fb5fc..f6664049f46d 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -414,6 +417,7 @@ static const struct mt_class mt_classes[] = { +@@ -422,6 +425,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -331,7 +331,7 @@ index 08fee06fb5fc..f6664049f46d 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1395,6 +1399,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1403,6 +1407,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -341,7 +341,7 @@ index 08fee06fb5fc..f6664049f46d 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1422,6 +1429,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1430,6 +1437,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -363,7 +363,7 @@ index 08fee06fb5fc..f6664049f46d 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1443,6 +1465,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1451,6 +1473,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -371,7 +371,7 @@ index 08fee06fb5fc..f6664049f46d 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1450,6 +1473,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1458,6 +1481,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -391,7 +391,7 @@ index 08fee06fb5fc..f6664049f46d 100644 /* let hid-core decide for the others */ return 0; } -@@ -1459,11 +1495,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1467,11 +1503,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -413,7 +413,7 @@ index 08fee06fb5fc..f6664049f46d 100644 return 0; } -@@ -1641,6 +1687,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1646,6 +1692,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index 08fee06fb5fc..f6664049f46d 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1689,6 +1771,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1694,6 +1776,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 08fee06fb5fc..f6664049f46d 100644 default: suffix = "UNKNOWN"; break; -@@ -1771,30 +1860,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1779,30 +1868,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 08fee06fb5fc..f6664049f46d 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1803,8 +1868,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1811,8 +1876,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 08fee06fb5fc..f6664049f46d 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -1941,13 +2007,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -1949,13 +2015,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 08fee06fb5fc..f6664049f46d 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1956,12 +2033,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -1964,12 +2041,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); @@ -571,5 +571,5 @@ index 08fee06fb5fc..f6664049f46d 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0010-surface-shutdown.patch b/patches/6.14/0011-surface-shutdown.patch similarity index 74% rename from patches/6.14/0010-surface-shutdown.patch rename to patches/6.14/0011-surface-shutdown.patch index d761cea88b..8dafbd31fd 100644 --- a/patches/6.14/0010-surface-shutdown.patch +++ b/patches/6.14/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 +From 26f09bed8d9daf48f62882e9e0307f2c81130870 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 35270172c833..529779994ef6 100644 +index f57ea36d125d..cdb74ec6c082 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,10 +37,10 @@ index 35270172c833..529779994ef6 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 8103bc24a54e..e8fa8d810925 100644 +index 82b21e34c545..ccf29cfa7082 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6301,3 +6301,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6316,3 +6316,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -81,24 +81,17 @@ index 8103bc24a54e..e8fa8d810925 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 4e77c4230c0a..a4b0e6ef6cfe 100644 +index 47b31ad724fa..c571fdca6c5f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -477,13 +477,14 @@ struct pci_dev { - unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ - unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ - unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ - unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ +@@ -476,6 +476,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ + unsigned int no_shutdown:1; /* Do not touch device on shutdown */ - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; /* pci_enable_device has been called */ - - spinlock_t pcie_cap_lock; /* Protects RMW ops in capability accessors */ - u32 saved_config_space[16]; /* Config space saved at suspend time */ - struct hlist_head saved_cap_space; - struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ - struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0011-surface-gpe.patch b/patches/6.14/0012-surface-gpe.patch similarity index 92% rename from patches/6.14/0011-surface-gpe.patch rename to patches/6.14/0012-surface-gpe.patch index cb83acb03c..605d05eba6 100644 --- a/patches/6.14/0011-surface-gpe.patch +++ b/patches/6.14/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 8120dc21068acfe547e9c6d1cced417e5931c7ad Mon Sep 17 00:00:00 2001 +From 0ea6591811ba84ac67dc7bb320d2048e949f7aad Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -12,7 +12,7 @@ Patchset: surface-gpe 1 file changed, 17 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index 62fd4004db31..103fc4468262 100644 +index b359413903b1..b4496db79f39 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { @@ -47,5 +47,5 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0013-cameras.patch b/patches/6.14/0013-cameras.patch new file mode 100644 index 0000000000..c6df5892ab --- /dev/null +++ b/patches/6.14/0013-cameras.patch @@ -0,0 +1,734 @@ +From 8678f0c1ed1a9d4f5cad1e0c0c677630a242d4bd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 9f4efa8f75a6..7c7ef03cafa4 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2204,6 +2204,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.49.0 + +From 069b8c0dd7460410d2e4d333bc533221d709cb17 Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 3735ed60032d..71cccee6e4a9 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -44,6 +44,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -213,12 +220,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -1910,6 +1919,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2206,6 +2218,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4506,6 +4521,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4553,6 +4580,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.49.0 + +From 5bc57f06d3dc085a2a0757fc5c35be36c2d6d341 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 81ac4c691963..f453c9043042 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.49.0 + +From c7a4afe01bfd24fbfc3735d1b60f08be3aef0b81 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 092252eb95a8..7a73d5f903a9 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -81,12 +81,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, unsigned long gpio_flags) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ { } ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ gpio_flags ^= GPIO_ACTIVE_LOW; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, gpio_flags); + if (ret) +-- +2.49.0 + +From 9ab2f02228baf5661844d4ba55810273b75cb456 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.49.0 + +From 4cfbc183671a5e27fb1808a0489dc4053ff970aa Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index cb153ce42c45..f11b499e14bb 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.49.0 + +From 6bede17be7b28d507138775eda22c15c020ee22d Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index f453c9043042..b8ad6b413e8b 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.49.0 + +From 4b91d36e045045a2f5029a47b33984c33a1d58cf Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.49.0 + +From 4606e818fd812630708c340acdc7a493d703842d Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 2b27d043921c..22a8c20de32a 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -985,6 +985,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 6ad52e219ec6..3519b4c32c9e 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -91,6 +91,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_UPBOARD) += leds-upboard.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.49.0 + +From 2666871d2780d86053ac2d61350de05de6888204 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.49.0 + diff --git a/patches/6.14/0013-amd-gpio.patch b/patches/6.14/0014-amd-gpio.patch similarity index 87% rename from patches/6.14/0013-amd-gpio.patch rename to patches/6.14/0014-amd-gpio.patch index 93c8956a23..120f6c51b4 100644 --- a/patches/6.14/0013-amd-gpio.patch +++ b/patches/6.14/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 28b8120e4f9b02ec49ccedd036557552a1aee5dc Mon Sep 17 00:00:00 2001 +From dc693e53aeaa7bcfea526f8867a3c2c3d027e7ef Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 4efecac49863..88377bb0d137 100644 +index dae6a73be40e..f401a6676b5e 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -32,7 +32,7 @@ index 4efecac49863..88377bb0d137 100644 #include #include -@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1169,6 +1170,17 @@ static void __init mp_config_acpi_legacy_irqs(void) } } @@ -50,7 +50,7 @@ index 4efecac49863..88377bb0d137 100644 /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) +@@ -1225,6 +1237,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, acpi_gbl_FADT.sci_interrupt); @@ -63,9 +63,9 @@ index 4efecac49863..88377bb0d137 100644 mp_config_acpi_legacy_irqs(); -- -2.47.1 +2.49.0 -From 1b801d759aced457e5508cf931fa849400233b92 Mon Sep 17 00:00:00 2001 +From 61a2673dc1feba27dea028f0e373081a19f3b6f6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,10 +80,10 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 88377bb0d137..c58f26918b17 100644 +index f401a6676b5e..fe3df37bfaff 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1172,12 +1172,19 @@ static void __init mp_config_acpi_legacy_irqs(void) static const struct dmi_system_id surface_quirk[] __initconst = { { @@ -105,5 +105,5 @@ index 88377bb0d137..c58f26918b17 100644 }; -- -2.47.1 +2.49.0 diff --git a/patches/6.14/0014-rtc.patch b/patches/6.14/0015-rtc.patch similarity index 96% rename from patches/6.14/0014-rtc.patch rename to patches/6.14/0015-rtc.patch index 784921d06d..a46655ddf9 100644 --- a/patches/6.14/0014-rtc.patch +++ b/patches/6.14/0015-rtc.patch @@ -1,4 +1,4 @@ -From 0a6b868f61d7564bc898ac30c84fbf3c34fb7368 Mon Sep 17 00:00:00 2001 +From 15bf9fcbacae64d8a208be07828b4aa7ae031482 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index b831cb8e53dc..78bd0f926505 100644 +index 825c2a8acea4..74612088ac5f 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, @@ -106,5 +106,5 @@ index b831cb8e53dc..78bd0f926505 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.47.1 +2.49.0 From 25a944c01000aac020cb6cbf679452ee1159d282 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 02:38:02 +0200 Subject: [PATCH 098/236] .github/workflows: Add support for Fedora 42 --- .github/workflows/fedora-42.yml | 125 ++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 .github/workflows/fedora-42.yml diff --git a/.github/workflows/fedora-42.yml b/.github/workflows/fedora-42.yml new file mode 100644 index 0000000000..8df6f1ab64 --- /dev/null +++ b/.github/workflows/fedora-42.yml @@ -0,0 +1,125 @@ +name: Fedora 42 + +env: + FEDORA: 42 + GPG_KEY_ID: 56C464BAAC421453 + +on: + push: + tags: + - 'fedora-42-*' + + repository_dispatch: + workflow_dispatch: + +jobs: + build: + name: Build Kernel + runs-on: ubuntu-latest + steps: + - name: Maximize disk space + uses: easimon/maximize-build-space@master + with: + root-reserve-mb: 5120 + remove-dotnet: true + remove-android: true + remove-docker-images: true + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Initialize containers + run: | + bash ./.github/scripts/container/create.sh \ + registry.fedoraproject.org/fedora:${{ env.FEDORA }} + + - name: Install build dependencies + run: | + bash ./.github/scripts/container/exec.sh \ + -- \ + bash ./.github/scripts/package/fedora.sh setup-builddeps + + - name: Setup secureboot certificate + env: + SB_KEY: ${{ secrets.SURFACE_SB_KEY }} + run: | + bash ./.github/scripts/container/exec.sh \ + -e SB_KEY \ + -- \ + bash ./.github/scripts/package/fedora.sh setup-secureboot + + - name: Build packages + run: | + bash ./.github/scripts/container/exec.sh \ + -- \ + bash ./.github/scripts/package/fedora.sh build-packages + + - name: Sign packages + env: + GPG_KEY: ${{ secrets.LINUX_SURFACE_GPG_KEY }} + run: | + bash ./.github/scripts/container/exec.sh \ + -e GPG_KEY \ + -e GPG_KEY_ID \ + -- \ + bash ./.github/scripts/package/fedora.sh sign-packages + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: fedora-${{ env.FEDORA }}-latest + path: pkg/fedora/kernel-surface/out/x86_64 + + release: + name: Publish release + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/') + needs: [build] + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: fedora-${{ env.FEDORA }}-latest + path: fedora-${{ env.FEDORA }}-latest + + - name: Upload assets + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + file: ./*-latest/* + tag: ${{ github.ref }} + overwrite: true + file_glob: true + + repo: + name: Update package repository + needs: [release] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: fedora-${{ env.FEDORA }}-latest + path: fedora-${{ env.FEDORA }}-latest + + - name: Initialize containers + run: | + bash ./.github/scripts/container/create.sh \ + registry.fedoraproject.org/fedora:${{ env.FEDORA }} + + - name: Update repository + env: + SURFACEBOT_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + GIT_REF: ${{ github.ref }} + BRANCH_STAGING: u/staging + run: | + bash ./.github/scripts/container/exec.sh \ + -e SURFACEBOT_TOKEN \ + -e GIT_REF \ + -e BRANCH_STAGING \ + -e GITHUB_REPOSITORY \ + -- \ + bash ./.github/scripts/repository/fedora.sh ${{ env.FEDORA }} From 256537c75d6d2a37c7eb5e7a3979dc2862576ab2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 02:40:53 +0200 Subject: [PATCH 099/236] Update Arch kernel to v6.14.2 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- pkg/arch/kernel/0007-surface-sam.patch | 2 +- .../kernel/0008-surface-sam-over-hid.patch | 2 +- pkg/arch/kernel/0009-surface-button.patch | 2 +- pkg/arch/kernel/0010-surface-typecover.patch | 2 +- pkg/arch/kernel/0011-surface-shutdown.patch | 2 +- pkg/arch/kernel/0012-surface-gpe.patch | 2 +- pkg/arch/kernel/0013-cameras.patch | 2 +- pkg/arch/kernel/0014-amd-gpio.patch | 2 +- pkg/arch/kernel/0015-rtc.patch | 2 +- pkg/arch/kernel/PKGBUILD | 36 +++++++++---------- pkg/arch/kernel/surface.config | 2 +- 17 files changed, 34 insertions(+), 34 deletions(-) diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 6b2cd21cd9..96dd8af4bb 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.13/0001-secureboot.patch \ No newline at end of file +../../../patches/6.14/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3.patch b/pkg/arch/kernel/0002-surface3.patch index 9d51dc679e..ad70e0813d 120000 --- a/pkg/arch/kernel/0002-surface3.patch +++ b/pkg/arch/kernel/0002-surface3.patch @@ -1 +1 @@ -../../../patches/6.13/0002-surface3.patch \ No newline at end of file +../../../patches/6.14/0002-surface3.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index 274642101f..8c498e0963 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.13/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.14/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index 78aac27bab..dd86ef8d3c 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.13/0004-ath10k.patch \ No newline at end of file +../../../patches/6.14/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index 46e4786335..ae82eb0b50 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.13/0005-ipts.patch \ No newline at end of file +../../../patches/6.14/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index 2c4cedf34a..fd7f0f2f30 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.13/0006-ithc.patch \ No newline at end of file +../../../patches/6.14/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch index 9d50d75414..a4db0ba73a 120000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -1 +1 @@ -../../../patches/6.13/0007-surface-sam.patch \ No newline at end of file +../../../patches/6.14/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch index d6c5aa570e..8d0eae142b 120000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -1 +1 @@ -../../../patches/6.13/0008-surface-sam-over-hid.patch \ No newline at end of file +../../../patches/6.14/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch index 9a3c5cece4..c504a293b4 120000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -1 +1 @@ -../../../patches/6.13/0009-surface-button.patch \ No newline at end of file +../../../patches/6.14/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch index c15115cb19..fd9dc210b6 120000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -1 +1 @@ -../../../patches/6.13/0010-surface-typecover.patch \ No newline at end of file +../../../patches/6.14/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch index 586b5370e7..d47226f64f 120000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -1 +1 @@ -../../../patches/6.13/0011-surface-shutdown.patch \ No newline at end of file +../../../patches/6.14/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch index 154bf83cd7..405637eede 120000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -1 +1 @@ -../../../patches/6.13/0012-surface-gpe.patch \ No newline at end of file +../../../patches/6.14/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch index 79798f0153..222488ce24 120000 --- a/pkg/arch/kernel/0013-cameras.patch +++ b/pkg/arch/kernel/0013-cameras.patch @@ -1 +1 @@ -../../../patches/6.13/0013-cameras.patch \ No newline at end of file +../../../patches/6.14/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch index 57b3a9beb7..31f5bdc0cb 120000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -1 +1 @@ -../../../patches/6.13/0014-amd-gpio.patch \ No newline at end of file +../../../patches/6.14/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch index ca9aa24baf..84733bb558 120000 --- a/pkg/arch/kernel/0015-rtc.patch +++ b/pkg/arch/kernel/0015-rtc.patch @@ -1 +1 @@ -../../../patches/6.13/0015-rtc.patch \ No newline at end of file +../../../patches/6.14/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index e88dfd420b..5ff90a9a0a 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.13.6.arch1 +pkgver=6.14.2.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('9c6c97b099ac0340c12355f58c553cbf2e27a89e274c6d0a188d5b4fe1700ccc' +sha256sums=('8fb801ac0004d22dbfc498266b156f13148272737ae42514169e7a56d72fd673' 'a6a234cd982d21f0d7daa3ba921293e450abd87ff5d7474d4a153b3f34cfabc5' - '8276bbf41baf9ca10749b46c6d8f3e641b2aeaa3492eefaeb6c4f404c18e3de5' + '8a68dbf5e7875f0d6a99c6aeb1dc913cc320fcb4e29c7fe388dc2ed7d81ac76b' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '12cb726d3ef7caeb7a8fb29488d26a33725f485c47a067ed3ff7b73a338478de' - 'eb5f12d39c6ddedf00de709dcddb2a5df08ce0f01d831ab6b0fc7cd816a9110c' - '013aacb2ef594f5b484b788799cee2e891827e09660ef119c157494141076155' - 'a3bca0c32b90c9ded47797c21952119d81bb7d0c6181c70103846e9eb8da3d45' - '2943ac9984fd05f75a31f53f9176837ba59caf72cca6105b4df2a9f72d95ceb4' - 'f389649f7c7286252e2ef531a4cfc69c12bb1f08f1c95bf81187c67e272f13b5' - 'da69177bc18a3897ec64906bafde1d37faf378604185ee74e64d5e5a7ef4b9df' - 'fa3614f0115694056631d471902d8bc40a7ee6063059cfd7210a6ca98a577041' - '9d3bf1705dc162a50e241bff1472aad05161c4656d19234f7ae61238929ad39b' - 'b7f221ddf8f4c1005876b286a17d25625657f88ed02bd6e12ef7f400c63f473a' - '2da0d1990890f4e01ffbf58b832d6e4834837ffb4a6f6cac8da696078449c8d6' - 'af784ad1d215236eae70597a723c3b96725d1416c3e6fa261fe731151e52df3f' - '6e46d9b1a6f1d91003438129ec61ffca1adf8a0b0b2a694dd7759239eb72c031' - '91bff8fa20a8cd1e000fd0f151d7b61df234a416add957e330ec885b8552b9fd' - '9afca88db82adddef56f88217f5d5273b05a449e11b702bbf0dadc4d28f93c58') + '77020395ec2fa3dcc609b9c984fec7f97fae196f0a24436031abbd4988b86300' + 'd73b19dc2b070272ffeffcbae862691ed03fb215e8f232b954fe9f6ed509e80c' + '718fd1b9cfbb0818235f78e440890f989dd969f784ff0e4aee52c36a078ca126' + 'cda4ef1533326aace8562d2a5fe4300f2fc3773ec11f7c2550ca4876e1139018' + 'a05467f5825e279e189b2ca926efe698077769b70428e8f61689d8e0f70c6c39' + '2d141c2dec6190d5bd51ecb82e79bdcbc0babe64b3299088d45a6a267acbb424' + '814be3c48392cdcf6b5df4575cb87e91839cc2b89750a3646c99357ab565cf1a' + '18f602335a757f81235c749650f403029fccc590317c61fd3d8842678e49b16d' + '7f42df95c3efb058f716776e21391a423083792063ed7693c3293f6556f74935' + '72be9823fd1bad0a039bb2e4b55997030f8e98b5144ed3c5c6f85d6995426cf9' + 'cae8e878df9c8590defe5e3bc01ce54ed0b98db9df1077fd9e5af175f308bbc5' + 'f19165e6c43a37d670f47f43505786ba0f788b06003918c2d0443c287cfb281a' + '21d9064e2d3be7b70bee5347d8dc748068ed1ad18f8f357a0e88fd73e16dbd77' + '92f88078a04a37706a1ed8ca04004c4318ddecb746804a2abd73f2342a37200e' + 'c3af5556d9d872f7d2316728e67a7a9cb77041b687e517a906f03e14a4e58e54') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index dbabc66c35..2eb0fdb85f 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.13.config \ No newline at end of file +../../../configs/surface-6.14.config \ No newline at end of file From 79592057c0806943c6725cb776c30b5f5647d6b3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 02:52:08 +0200 Subject: [PATCH 100/236] Update Debian kernel to v6.14.2 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index aa7ce3cf73..f046e15902 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.13.6" +KERNEL_VERSION="6.14.2" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From c89854109324249a98abd1cff06afa4f2f5d1e8f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 02:55:55 +0200 Subject: [PATCH 101/236] Update Fedora kernels to v6.14.2 --- pkg/fedora/kernel-surface/build-linux-surface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 93ca2d1829..d0c8854708 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.13.6-0" +PACKAGE_TAG = "kernel-6.14.2-0" ## ## The release number of the modified kernel package. @@ -79,7 +79,7 @@ kernel_major = ".".join(kernel_version.split(".")[:2]) # Determine the patches directory and config file. -patches = linux_surface / "patches" / f"{kernel_major}-fedora" +patches = linux_surface / "patches" / kernel_major config = linux_surface / "configs" / ("surface-%s.config" % kernel_major) sb_cert = script / "secureboot" / "MOK.crt" From ac445b51a1272ead9f783a42d881329c950d30fe Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 03:06:44 +0200 Subject: [PATCH 102/236] pkg/debian: Update Debian-specific patches --- ...-integrity-Only-use-machine-keyring-.patch | 4 ++-- ...sallow-unprivileged-CLONE_NEWUSER-by.patch | 14 +++++++------- ...uild-Copy-config-to-target-directory.patch | 19 +++++++++---------- ...001-kbuild-Link-sign-file-statically.patch | 6 +++--- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch index c13278103c..a5b4568a8f 100644 --- a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch +++ b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch @@ -1,4 +1,4 @@ -From 556d277d8397c8bd0c5889a309e50290d491e41c Mon Sep 17 00:00:00 2001 +From 1fb0cb1a5de985b6b8728f6a39660fcd5df29977 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 22:54:05 +0100 Subject: [PATCH] Partially revert "integrity: Only use machine keyring when @@ -37,5 +37,5 @@ index a401640a63cd..a1ad244cbf86 100644 static bool __init trust_moklist(void) -- -2.45.2 +2.49.0 diff --git a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch index 436ec5305e..6ffe47c8d6 100644 --- a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch +++ b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch @@ -1,4 +1,4 @@ -From 8da9938f2e7d28a5ae834bec723bc283dc62470f Mon Sep 17 00:00:00 2001 +From d70cb56d43efddd10d4263f2af24f52fb81137b9 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Fri, 31 May 2013 19:12:12 +0100 Subject: [PATCH] add sysctl to disallow unprivileged CLONE_NEWUSER by default @@ -20,7 +20,7 @@ Signed-off-by: Serge Hallyn 3 files changed, 32 insertions(+) diff --git a/kernel/fork.c b/kernel/fork.c -index 9da032802e34..f3ad270eb96b 100644 +index ca2ca3884f76..d9591a8a6ead 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -119,6 +119,12 @@ @@ -36,7 +36,7 @@ index 9da032802e34..f3ad270eb96b 100644 /* * Minimum number of threads to boot the kernel */ -@@ -2169,6 +2175,10 @@ __latent_entropy struct task_struct *copy_process( +@@ -2171,6 +2177,10 @@ __latent_entropy struct task_struct *copy_process( if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -47,7 +47,7 @@ index 9da032802e34..f3ad270eb96b 100644 /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. -@@ -3322,6 +3332,12 @@ int ksys_unshare(unsigned long unshare_flags) +@@ -3324,6 +3334,12 @@ int ksys_unshare(unsigned long unshare_flags) if (unshare_flags & CLONE_NEWNS) unshare_flags |= CLONE_FS; @@ -61,7 +61,7 @@ index 9da032802e34..f3ad270eb96b 100644 if (err) goto bad_unshare_out; diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 5c9202cb8f59..71102bca044e 100644 +index cb57da499ebb..5e9ae0e6a727 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -135,6 +135,10 @@ static enum sysctl_writes_mode sysctl_writes_strict = SYSCTL_WRITES_STRICT; @@ -75,7 +75,7 @@ index 5c9202cb8f59..71102bca044e 100644 #endif /* CONFIG_SYSCTL */ /* -@@ -1617,6 +1621,15 @@ static struct ctl_table kern_table[] = { +@@ -1617,6 +1621,15 @@ static const struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, @@ -106,5 +106,5 @@ index aa0b2e47f2f2..222bb2b40b73 100644 static DEFINE_MUTEX(userns_state_mutex); -- -2.48.1 +2.49.0 diff --git a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch index 516bbde169..75376c4af9 100644 --- a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch +++ b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch @@ -1,25 +1,24 @@ -From 6cf53165cd3876128648dadb76a718d02692e19d Mon Sep 17 00:00:00 2001 +From 95802baf706303292278c2ae4347f5c3aa9dcece Mon Sep 17 00:00:00 2001 From: Maximilian Luz -Date: Sun, 9 Mar 2025 01:33:54 +0100 +Date: Sun, 20 Apr 2025 03:02:20 +0200 Subject: [PATCH] kbuild: Copy config to target directory -Partial revert of aaed5c7739be ("kbuild: slim down package for building -external modules"). Re-incldue the .config file. --- - scripts/package/install-extmod-build | 2 ++ - 1 file changed, 2 insertions(+) + scripts/package/install-extmod-build | 3 +++ + 1 file changed, 3 insertions(+) diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build -index d3c5b104c063..d98da1f2bf02 100755 +index b96538787f3d..718bd64d060e 100755 --- a/scripts/package/install-extmod-build +++ b/scripts/package/install-extmod-build -@@ -83,4 +83,6 @@ if [ "${CC}" != "${HOSTCC}" ]; then - rm -f "${destdir}/Kbuild" "${destdir}/scripts/Kbuild" +@@ -68,4 +68,7 @@ if [ "${CC}" != "${HOSTCC}" ]; then + rm -f "${destdir}/scripts/Kbuild" fi +# copy .config manually to be where it's expected to be +cp "${KCONFIG_CONFIG}" "${destdir}/.config" ++ find "${destdir}" \( -name '.*.cmd' -o -name '*.o' \) -delete -- -2.48.1 +2.49.0 diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index 7104412d3c..eee7ae8e73 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -1,4 +1,4 @@ -From 71701f82718799df961b252fef44e2a75f31e408 Mon Sep 17 00:00:00 2001 +From b1c72eb34eabfd56cbe5a1b98b827aded4917125 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:10:28 +0200 Subject: [PATCH] kbuild: Link sign-file statically @@ -8,7 +8,7 @@ Subject: [PATCH] kbuild: Link sign-file statically 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile b/scripts/Makefile -index fe56eeef09dd..e614f49b17e5 100644 +index 46f860529df5..7846e18ef5d8 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -29,7 +29,7 @@ HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include @@ -21,5 +21,5 @@ index fe56eeef09dd..e614f49b17e5 100644 ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) -- -2.45.2 +2.49.0 From ae13705b62dc4ca3ffd73b136816bc2600ef630f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 21 Jun 2025 21:38:00 +0200 Subject: [PATCH 103/236] Update v6.14 patches Changes: - Rebase onto v6.14.11 Links: - kernel: https://github.com/linux-surface/kernel/commit/15bf9fcbacae64d8a208be07828b4aa7ae031482 --- patches/6.14/0001-secureboot.patch | 14 +-- patches/6.14/0002-surface3.patch | 8 +- patches/6.14/0003-mwifiex.patch | 18 ++-- patches/6.14/0004-ath10k.patch | 4 +- patches/6.14/0005-ipts.patch | 30 +++--- patches/6.14/0006-ithc.patch | 20 ++-- patches/6.14/0007-surface-sam.patch | 8 +- patches/6.14/0008-surface-sam-over-hid.patch | 8 +- patches/6.14/0009-surface-button.patch | 8 +- patches/6.14/0010-surface-typecover.patch | 14 +-- patches/6.14/0011-surface-shutdown.patch | 8 +- patches/6.14/0012-surface-gpe.patch | 4 +- patches/6.14/0013-cameras.patch | 108 +++++-------------- patches/6.14/0014-amd-gpio.patch | 22 ++-- patches/6.14/0015-rtc.patch | 4 +- 15 files changed, 111 insertions(+), 167 deletions(-) diff --git a/patches/6.14/0001-secureboot.patch b/patches/6.14/0001-secureboot.patch index a850f2286e..de8ed744dc 100644 --- a/patches/6.14/0001-secureboot.patch +++ b/patches/6.14/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 021ec07abb3238472d89815c934fb3dc07f1b29e Mon Sep 17 00:00:00 2001 +From 3ae65e76bec1728fd475ccdbef0dd0e162f78f71 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.49.0 +2.50.0 -From 4c1408f0a6a9ee5b1998253f4f30c04eb1e96240 Mon Sep 17 00:00:00 2001 +From 12328f0f896d94be374d0dc13aa233039b3d3c8e Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,10 +53,10 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index fb8752b42ec8..d46bb052b3a1 100644 +index a8e98f75b610..fc8abda3dfd6 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3154,6 +3154,11 @@ +@@ -3173,6 +3173,11 @@ to extract confidential information from the kernel are also disabled. @@ -69,7 +69,7 @@ index fb8752b42ec8..d46bb052b3a1 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 10a01af63a80..e53e4a86e4cc 100644 +index b129ed1d25a8..547953e14503 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -37,6 +37,7 @@ @@ -108,5 +108,5 @@ index 10a01af63a80..e53e4a86e4cc 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0002-surface3.patch b/patches/6.14/0002-surface3.patch index b45cfd8644..9b04db3d18 100644 --- a/patches/6.14/0002-surface3.patch +++ b/patches/6.14/0002-surface3.patch @@ -1,4 +1,4 @@ -From 97e443f4ec202c66165990d72c05aa28c359b31e Mon Sep 17 00:00:00 2001 +From bbe0c33ca658e0081e2501255aae273b312e47bd Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,9 +97,9 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.49.0 +2.50.0 -From ebacd5e19eb63db32a538bab0d9e5b44737a24bb Mon Sep 17 00:00:00 2001 +From a948106e29a2142f5a553a6431d174e2b5efcb52 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -230,5 +230,5 @@ index 6074b7730e86..6aa3e1d6f160 100644 } -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0003-mwifiex.patch b/patches/6.14/0003-mwifiex.patch index 3143915c46..0249d9c2df 100644 --- a/patches/6.14/0003-mwifiex.patch +++ b/patches/6.14/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From fd57091b497bdd3467f99e6d79d3d7319b65938f Mon Sep 17 00:00:00 2001 +From 323568e951309bae33b7c468ddd927c921b4e41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.49.0 +2.50.0 -From 9d16ab5d6b0253b5e5d28adab637ac0405052124 Mon Sep 17 00:00:00 2001 +From bfe0140220b8e0c37fa3e969fef6a2f32c354dd7 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.49.0 +2.50.0 -From f44651e18ec650050bb04a1134209da6109a8232 Mon Sep 17 00:00:00 2001 +From 206186b3659beb6c47e32ee9b6dae62c96d9bcbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 699ff21d9767..3568d5d4906e 100644 +index b15f3ed767c5..c314adde36a1 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; @@ -367,7 +367,7 @@ index 699ff21d9767..3568d5d4906e 100644 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ -@@ -441,6 +442,7 @@ static const struct usb_device_id quirks_table[] = { +@@ -469,6 +470,7 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, @@ -375,7 +375,7 @@ index 699ff21d9767..3568d5d4906e 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3931,6 +3933,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3990,6 +3992,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 699ff21d9767..3568d5d4906e 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0004-ath10k.patch b/patches/6.14/0004-ath10k.patch index e50e6c5b27..dfd405561d 100644 --- a/patches/6.14/0004-ath10k.patch +++ b/patches/6.14/0004-ath10k.patch @@ -1,4 +1,4 @@ -From bb582f0942d5b505c0c2744c5a24e1711ae9ce8f Mon Sep 17 00:00:00 2001 +From 1204ce622f4a487d274e369dccb3c6e16031f2bf Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index b3294287bce1..2936fdae823c 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0005-ipts.patch b/patches/6.14/0005-ipts.patch index 7519047a5e..608380fa99 100644 --- a/patches/6.14/0005-ipts.patch +++ b/patches/6.14/0005-ipts.patch @@ -1,4 +1,4 @@ -From b89f20bfa13868323f9875acfe07e9d8f618329f Mon Sep 17 00:00:00 2001 +From 490277cbb9ac90432c89b433e15f4cb4c4bb79ff Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index a5f88ec97df7..e379dc2373b5 100644 +index bc40b940ae21..45fbd856d416 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index a5f88ec97df7..e379dc2373b5 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index d6ff9d82ae94..a1b714505f43 100644 +index 3f9c60b579ae..853a67753333 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index d6ff9d82ae94..a1b714505f43 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.49.0 +2.50.0 -From 8690c582cf49e817cff1f4ff216c4c1828682c78 Mon Sep 17 00:00:00 2001 +From a57f5264ddb9f3407cf83d0dc83aa0d7b1a916d3 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 25d31f8c129a..3735ed60032d 100644 +index 580d24dd4edd..93c18f862e6c 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -111,7 +111,7 @@ index 25d31f8c129a..3735ed60032d 100644 check_tylersburg_isoch(); /* -@@ -4493,6 +4506,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4460,6 +4473,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index 25d31f8c129a..3735ed60032d 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4528,6 +4553,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4498,6 +4523,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index 25d31f8c129a..3735ed60032d 100644 { if (risky_device(dev)) -- -2.49.0 +2.50.0 -From 458d45bfbecaad616ed515d82abe8598fe8c2b0e Mon Sep 17 00:00:00 2001 +From c2ccf49147c5ba07a5602db0de6fa6c59903a79a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,10 +211,10 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index dfc245867a46..f91ba8a06cfc 100644 +index 76be97c5fc2f..0d1446b45c36 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1387,6 +1387,8 @@ source "drivers/hid/surface-hid/Kconfig" +@@ -1402,6 +1402,8 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/intel-thc-hid/Kconfig" @@ -224,10 +224,10 @@ index dfc245867a46..f91ba8a06cfc 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 0abfe51704a0..c86c9e80d225 100644 +index c7ecfbb3e228..7b2939c8a477 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -172,3 +172,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ +@@ -173,3 +173,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ @@ -3239,5 +3239,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0006-ithc.patch b/patches/6.14/0006-ithc.patch index f3e96a5669..97e5902f0a 100644 --- a/patches/6.14/0006-ithc.patch +++ b/patches/6.14/0006-ithc.patch @@ -1,4 +1,4 @@ -From 85f3a4111005d23749f1a5b0424264ba38bbb3f4 Mon Sep 17 00:00:00 2001 +From e4540875b9b5d3d9178aef6bf8bcecc5cddc1c4a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,10 +10,10 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index ad795c772f21..2c10bca9e06b 100644 +index 3bc2a03cceca..e4c95c0a87f9 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c -@@ -388,6 +388,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) +@@ -380,6 +380,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) data.busmatch_count = 0; pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); @@ -37,9 +37,9 @@ index ad795c772f21..2c10bca9e06b 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.49.0 +2.50.0 -From 3e386a2ed36c9d620f4de23d671daa75a509d797 Mon Sep 17 00:00:00 2001 +From 43a2c8fea689f6e377fb0790b4e611beec6c699c Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,10 +86,10 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index f91ba8a06cfc..e945736e216f 100644 +index 0d1446b45c36..b8315f388240 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1389,6 +1389,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" +@@ -1404,6 +1404,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" source "drivers/hid/ipts/Kconfig" @@ -99,10 +99,10 @@ index f91ba8a06cfc..e945736e216f 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index c86c9e80d225..046eb5fd8017 100644 +index 7b2939c8a477..a3c9274c0bef 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -174,3 +174,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ +@@ -175,3 +175,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ obj-$(CONFIG_HID_IPTS) += ipts/ @@ -2769,5 +2769,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0007-surface-sam.patch b/patches/6.14/0007-surface-sam.patch index a4d7a23739..b28b5cd0a3 100644 --- a/patches/6.14/0007-surface-sam.patch +++ b/patches/6.14/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 156b853c039f830407bea29f01bb6f3489c7c3e1 Mon Sep 17 00:00:00 2001 +From a5eb89dfb9f2544e3271c60658a683801b7a5c23 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -179,9 +179,9 @@ index 000000000000..f6c17c4e98d5 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.49.0 +2.50.0 -From 3dec366702ebcfb04f7805144eca4c943d19802b Mon Sep 17 00:00:00 2001 +From b9ffcd1963e0995fde893e9ae8828ade30b95d64 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -207,5 +207,5 @@ index a594d5fcfcfd..07b03aa4fa7f 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0008-surface-sam-over-hid.patch b/patches/6.14/0008-surface-sam-over-hid.patch index 293932558f..bf44ccbc70 100644 --- a/patches/6.14/0008-surface-sam-over-hid.patch +++ b/patches/6.14/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From b0c24f19804345b57672cf54e5caa7ba473f3f26 Mon Sep 17 00:00:00 2001 +From 7a262cf2715615399d0c60816377df87009e326e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index d2499f302b50..77ce5ec3dd9e 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.49.0 +2.50.0 -From b27002518a3b386bc3c2d50d7e45c94148375aa4 Mon Sep 17 00:00:00 2001 +From 1d78f095f8b30bfaa11e2d6d282c5605140c895c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0009-surface-button.patch b/patches/6.14/0009-surface-button.patch index c0676281f3..b454cb615c 100644 --- a/patches/6.14/0009-surface-button.patch +++ b/patches/6.14/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 3e79d7b95f28bfcd981ca7db961407b2375307be Mon Sep 17 00:00:00 2001 +From 884c068a28164f2acedd3890fe7a07674ecbf9c0 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index b8cad415c62c..43b5d56383e3 100644 /* -- -2.49.0 +2.50.0 -From 8cbc63032afb8606805a14cc1c5f29d9105567c0 Mon Sep 17 00:00:00 2001 +From ffe10fa9dbb86acf7758091da53e8a420eeca7d0 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0010-surface-typecover.patch b/patches/6.14/0010-surface-typecover.patch index 233dd01264..47f7d989fd 100644 --- a/patches/6.14/0010-surface-typecover.patch +++ b/patches/6.14/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 79ab84535e4dd94a0ccf8159a52675f24eaca7a2 Mon Sep 17 00:00:00 2001 +From 5cba6349d24ff4122dd272b4b3582a470bceef9d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 8efbacc5bc34..4dfb3e3023af 100644 +index 53d68d20fb62..cf85b30b1d60 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index 8efbacc5bc34..4dfb3e3023af 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.49.0 +2.50.0 -From 76accddaf1b7b28acb671305efb2a71eee0ea4af Mon Sep 17 00:00:00 2001 +From 8623befd2c9aabf3664f379adb9b359525b8772d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -272,9 +272,9 @@ index e50887a6d22c..4ce18f21a141 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.49.0 +2.50.0 -From a10308974d385d1b666dd93ef16c5597c872199c Mon Sep 17 00:00:00 2001 +From 67a0ee9310d87cb3880d0fbde669f84cfbfeab4c Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -571,5 +571,5 @@ index 4ce18f21a141..f5e4d52bd2eb 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0011-surface-shutdown.patch b/patches/6.14/0011-surface-shutdown.patch index 8dafbd31fd..4fe55ac91c 100644 --- a/patches/6.14/0011-surface-shutdown.patch +++ b/patches/6.14/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 26f09bed8d9daf48f62882e9e0307f2c81130870 Mon Sep 17 00:00:00 2001 +From b19ebe86f0efac469f91581fe6ee53bce4586bc2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -81,10 +81,10 @@ index 82b21e34c545..ccf29cfa7082 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 47b31ad724fa..c571fdca6c5f 100644 +index 8e028620642f..5dea44aa163b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -476,6 +476,7 @@ struct pci_dev { +@@ -478,6 +478,7 @@ struct pci_dev { unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ @@ -93,5 +93,5 @@ index 47b31ad724fa..c571fdca6c5f 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0012-surface-gpe.patch b/patches/6.14/0012-surface-gpe.patch index 605d05eba6..cada29180e 100644 --- a/patches/6.14/0012-surface-gpe.patch +++ b/patches/6.14/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 0ea6591811ba84ac67dc7bb320d2048e949f7aad Mon Sep 17 00:00:00 2001 +From ca7157512287c654bd628c958f92b83764b2d3b1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index b359413903b1..b4496db79f39 100644 .ident = "Surface Book 1", .matches = { -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0013-cameras.patch b/patches/6.14/0013-cameras.patch index c6df5892ab..088647334f 100644 --- a/patches/6.14/0013-cameras.patch +++ b/patches/6.14/0013-cameras.patch @@ -1,4 +1,4 @@ -From 8678f0c1ed1a9d4f5cad1e0c0c677630a242d4bd Mon Sep 17 00:00:00 2001 +From 9f359d3b71901df093dd03d2ccb3daca01a8a339 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index 9f4efa8f75a6..7c7ef03cafa4 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.49.0 +2.50.0 -From 069b8c0dd7460410d2e4d333bc533221d709cb17 Mon Sep 17 00:00:00 2001 +From 566b4d441c1d2ac2d038f4c3231187cc4b74c507 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 3735ed60032d..71cccee6e4a9 100644 +index 93c18f862e6c..1acf7906fbb9 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -152,7 +152,7 @@ index 3735ed60032d..71cccee6e4a9 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4506,6 +4521,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4473,6 +4488,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index 3735ed60032d..71cccee6e4a9 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4553,6 +4580,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4523,6 +4550,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index 3735ed60032d..71cccee6e4a9 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.49.0 +2.50.0 -From 5bc57f06d3dc085a2a0757fc5c35be36c2d6d341 Mon Sep 17 00:00:00 2001 +From 62427236fd018fba1a6c7127efb2a45289d6aabd Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,65 +219,9 @@ index 81ac4c691963..f453c9043042 100644 return 0; -- -2.49.0 +2.50.0 -From c7a4afe01bfd24fbfc3735d1b60f08be3aef0b81 Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Thu, 2 Mar 2023 12:59:39 +0000 -Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E - -ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The -driver for this sensor expects a single pin named "enable", but on -some Microsoft Surface platforms the sensor is assigned a single -GPIO who's type flag is INT3472_GPIO_TYPE_RESET. - -Remap the GPIO pin's function from "reset" to "enable". This is done -outside of the existing remap table since it is a more widespread -discrepancy than that method is designed for. Additionally swap the -polarity of the pin to match the driver's expectation. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 092252eb95a8..7a73d5f903a9 100644 ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -81,12 +81,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - const char *func, unsigned long gpio_flags) - { - int ret; -+ const struct acpi_device_id ov7251_ids[] = { -+ { "INT347E" }, -+ { } -+ }; - - if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { - dev_warn(int3472->dev, "Too many GPIOs mapped\n"); - return -EINVAL; - } - -+ /* -+ * In addition to the function remap table we need to bulk remap the -+ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that -+ * expects its only GPIO pin to be called "enable" (and to have the -+ * opposite polarity). -+ */ -+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { -+ func = "enable"; -+ gpio_flags ^= GPIO_ACTIVE_LOW; -+ } -+ - ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, func, gpio_flags); - if (ret) --- -2.49.0 - -From 9ab2f02228baf5661844d4ba55810273b75cb456 Mon Sep 17 00:00:00 2001 +From ecc15ede9f86d97ea6fdca7d6641949ec40edbe2 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -292,10 +236,10 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf..9c1292ca8552 100644 +index 3226888d77e9..3bfe45b764f7 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c -@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) +@@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE: ret = ov7251_set_exposure(ov7251, ctrl->val); break; @@ -304,7 +248,7 @@ index 30f61e04ecaf..9c1292ca8552 100644 ret = ov7251_set_gain(ov7251, ctrl->val); break; case V4L2_CID_TEST_PATTERN: -@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) +@@ -1574,7 +1574,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, V4L2_CID_EXPOSURE, 1, 32, 1, 32); ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, @@ -314,9 +258,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.49.0 +2.50.0 -From 4cfbc183671a5e27fb1808a0489dc4053ff970aa Mon Sep 17 00:00:00 2001 +From db60cbc5de5c80f605a4db318cf34d58c69d6c95 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -365,9 +309,9 @@ index cb153ce42c45..f11b499e14bb 100644 if (ret < 0) goto out_cleanup; -- -2.49.0 +2.50.0 -From 6bede17be7b28d507138775eda22c15c020ee22d Mon Sep 17 00:00:00 2001 +From 10ac2f54fdf7c498010dd4239e9fa2e8d0d3c6ca Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -406,9 +350,9 @@ index f453c9043042..b8ad6b413e8b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.49.0 +2.50.0 -From 4b91d36e045045a2f5029a47b33984c33a1d58cf Mon Sep 17 00:00:00 2001 +From 5ce308dae49694842cb19eb0c35a799ec5760969 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -447,9 +391,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.49.0 +2.50.0 -From 4606e818fd812630708c340acdc7a493d703842d Mon Sep 17 00:00:00 2001 +From 6eb3985c1d119ec3e3452dcad3a26707cea4416f Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -472,10 +416,10 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 2b27d043921c..22a8c20de32a 100644 +index 8859e8fe292a..04ee65c9eec6 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig -@@ -985,6 +985,18 @@ config LEDS_TPS6105X +@@ -986,6 +986,18 @@ config LEDS_TPS6105X It is a single boost converter primarily for white LEDs and audio amplifiers. @@ -698,9 +642,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.49.0 +2.50.0 -From 2666871d2780d86053ac2d61350de05de6888204 Mon Sep 17 00:00:00 2001 +From 19e0f19874902ac5791da82f7a54b1b40cbdf877 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -730,5 +674,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0014-amd-gpio.patch b/patches/6.14/0014-amd-gpio.patch index 120f6c51b4..24f219aeee 100644 --- a/patches/6.14/0014-amd-gpio.patch +++ b/patches/6.14/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From dc693e53aeaa7bcfea526f8867a3c2c3d027e7ef Mon Sep 17 00:00:00 2001 +From cf85ecd3a2e278621062ebcf7406dc7aeb8a8faa Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index dae6a73be40e..f401a6676b5e 100644 +index 9fa321a95eb3..8914a922be2b 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -30,9 +30,9 @@ index dae6a73be40e..f401a6676b5e 100644 #include +#include - #include - #include -@@ -1169,6 +1170,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + #include + +@@ -1171,6 +1172,17 @@ static void __init mp_config_acpi_legacy_irqs(void) } } @@ -50,7 +50,7 @@ index dae6a73be40e..f401a6676b5e 100644 /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -@@ -1225,6 +1237,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) +@@ -1227,6 +1239,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, acpi_gbl_FADT.sci_interrupt); @@ -63,9 +63,9 @@ index dae6a73be40e..f401a6676b5e 100644 mp_config_acpi_legacy_irqs(); -- -2.49.0 +2.50.0 -From 61a2673dc1feba27dea028f0e373081a19f3b6f6 Mon Sep 17 00:00:00 2001 +From 24baea6b01abec92cb98122a380c3367f3e21d96 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,10 +80,10 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index f401a6676b5e..fe3df37bfaff 100644 +index 8914a922be2b..c43d0a553867 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -1172,12 +1172,19 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) static const struct dmi_system_id surface_quirk[] __initconst = { { @@ -105,5 +105,5 @@ index f401a6676b5e..fe3df37bfaff 100644 }; -- -2.49.0 +2.50.0 diff --git a/patches/6.14/0015-rtc.patch b/patches/6.14/0015-rtc.patch index a46655ddf9..5868fb75b5 100644 --- a/patches/6.14/0015-rtc.patch +++ b/patches/6.14/0015-rtc.patch @@ -1,4 +1,4 @@ -From 15bf9fcbacae64d8a208be07828b4aa7ae031482 Mon Sep 17 00:00:00 2001 +From 8491ddedc4b6a27c0b4d81c5ea1670ef050235bc Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 825c2a8acea4..74612088ac5f 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.49.0 +2.50.0 From 15af02b3c225e6ff61b0dcfe9505f7192645c1fd Mon Sep 17 00:00:00 2001 From: tabletseeker <148603424+tabletseeker@users.noreply.github.com> Date: Fri, 13 Jun 2025 16:59:07 +0000 Subject: [PATCH 104/236] Adding patches for Kernel 6.15 --- patches/6.15/0001-secureboot.patch | 112 + patches/6.15/0002-surface3.patch | 234 ++ patches/6.15/0003-mwifiex.patch | 400 +++ patches/6.15/0004-ath10k.patch | 120 + patches/6.15/0005-ipts.patch | 3243 ++++++++++++++++++ patches/6.15/0006-ithc.patch | 2773 +++++++++++++++ patches/6.15/0007-surface-sam.patch | 211 ++ patches/6.15/0008-surface-sam-over-hid.patch | 308 ++ patches/6.15/0009-surface-button.patch | 149 + patches/6.15/0010-surface-typecover.patch | 235 ++ patches/6.15/0011-surface-shutdown.patch | 97 + patches/6.15/0012-surface-gpe.patch | 51 + patches/6.15/0013-cameras.patch | 743 ++++ patches/6.15/0014-amd-gpio.patch | 108 + patches/6.15/0015-rtc.patch | 110 + 15 files changed, 8894 insertions(+) create mode 100644 patches/6.15/0001-secureboot.patch create mode 100644 patches/6.15/0002-surface3.patch create mode 100644 patches/6.15/0003-mwifiex.patch create mode 100644 patches/6.15/0004-ath10k.patch create mode 100644 patches/6.15/0005-ipts.patch create mode 100644 patches/6.15/0006-ithc.patch create mode 100644 patches/6.15/0007-surface-sam.patch create mode 100644 patches/6.15/0008-surface-sam-over-hid.patch create mode 100644 patches/6.15/0009-surface-button.patch create mode 100644 patches/6.15/0010-surface-typecover.patch create mode 100644 patches/6.15/0011-surface-shutdown.patch create mode 100644 patches/6.15/0012-surface-gpe.patch create mode 100644 patches/6.15/0013-cameras.patch create mode 100644 patches/6.15/0014-amd-gpio.patch create mode 100644 patches/6.15/0015-rtc.patch diff --git a/patches/6.15/0001-secureboot.patch b/patches/6.15/0001-secureboot.patch new file mode 100644 index 0000000000..a850f2286e --- /dev/null +++ b/patches/6.15/0001-secureboot.patch @@ -0,0 +1,112 @@ +From 021ec07abb3238472d89815c934fb3dc07f1b29e Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359b..a1bbedd989e4 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.49.0 + +From 4c1408f0a6a9ee5b1998253f4f30c04eb1e96240 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index fb8752b42ec8..d46bb052b3a1 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3154,6 +3154,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 10a01af63a80..e53e4a86e4cc 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -37,6 +37,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -92,7 +93,7 @@ void hibernate_release(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1434,6 +1435,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1492,3 +1499,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.49.0 + diff --git a/patches/6.15/0002-surface3.patch b/patches/6.15/0002-surface3.patch new file mode 100644 index 0000000000..b45cfd8644 --- /dev/null +++ b/patches/6.15/0002-surface3.patch @@ -0,0 +1,234 @@ +From 97e443f4ec202c66165990d72c05aa28c359b31e Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3 +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index 6c8fb7a4dde4..22797a53f4d8 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 51187b1e0ed2..bfb83ce8d8f8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.49.0 + +From ebacd5e19eb63db32a538bab0d9e5b44737a24bb Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Fri, 6 Dec 2019 23:10:30 +0900 +Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by + default + +On Arch Linux kernel at least after 4.19, touch input is broken after suspend +(s2idle). + + kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + +On recent stable Arch Linux kernel (at least after 5.1), touch input will +crash after the first touch. + + kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue + +I found on an affected system (Arch Linux kernel, etc.), the touchscreen +driver uses DMA mode by default. Then, we found some kernels with different +kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel +chromeos-4.19 [2]) will use PIO mode by default and no such issues there. + +So, this commit disables DMA mode on the touchscreen driver side as a quick +workaround to avoid touch input crash. +We may need to properly set up DMA mode to use the touchscreen driver with +DMA mode. + +You can still switch DMA/PIO mode if you want: + + switch to DMA mode (maybe broken) + echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma + back to PIO mode + echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma + +Link to issue: https://github.com/jakeday/linux-surface/issues/596 + +References: +[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config +[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 + +Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. +This commit made the driver use PIO by default and no touch input crash. +Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default +even without this commit. After this commit, it still uses PIO and confirmed +no functional changes regarding touch input. + +More details: + We can confirm which mode the touchscreen driver uses; first, enable + debug output: + + echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + + Then, try to make a touch input and see dmesg log + + (On Arch Linux kernel, uses DMA) + kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA + kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 + c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + + (On the kernels I referenced above, uses PIO) + kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO + kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 + 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Note (2025-03-08): This patch was originally dropped due to the +comments in [3]. However, according to the commments in [4] it is still +required. + +[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a +[4]: https://github.com/linux-surface/linux-surface/issues/1184 + +Patchset: surface3 +--- + drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c +index 6074b7730e86..6aa3e1d6f160 100644 +--- a/drivers/input/touchscreen/surface3_spi.c ++++ b/drivers/input/touchscreen/surface3_spi.c +@@ -25,6 +25,12 @@ + #define SURFACE3_REPORT_TOUCH 0xd2 + #define SURFACE3_REPORT_PEN 0x16 + ++bool use_dma = false; ++module_param(use_dma, bool, 0644); ++MODULE_PARM_DESC(use_dma, ++ "Disable DMA mode if you encounter touch input crash. " ++ "(default: false, disabled to avoid crash)"); ++ + struct surface3_ts_data { + struct spi_device *spi; + struct gpio_desc *gpiod_rst[2]; +@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) + return 0; + } + ++static bool surface3_spi_can_dma(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) ++{ ++ return use_dma; ++} ++ + static int surface3_spi_probe(struct spi_device *spi) + { + struct surface3_ts_data *data; +@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) + if (error) + return error; + ++ /* ++ * Set up DMA ++ * ++ * TODO: Currently, touch input with DMA seems to be broken. ++ * On 4.19 LTS, touch input will crash after suspend. ++ * On recent stable kernel (at least after 5.1), touch input will crash after ++ * the first touch. No problem with PIO on those kernels. ++ * Maybe we need to configure DMA here. ++ * ++ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 ++ */ ++ spi->controller->can_dma = surface3_spi_can_dma; ++ + return 0; + } + +-- +2.49.0 + diff --git a/patches/6.15/0003-mwifiex.patch b/patches/6.15/0003-mwifiex.patch new file mode 100644 index 0000000000..3143915c46 --- /dev/null +++ b/patches/6.15/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From fd57091b497bdd3467f99e6d79d3d7319b65938f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 5f997becdbaa..9a9929424513 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.49.0 + +From 9d16ab5d6b0253b5e5d28adab637ac0405052124 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a9929424513..2273e3029776 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.49.0 + +From f44651e18ec650050bb04a1134209da6109a8232 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 699ff21d9767..3568d5d4906e 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -441,6 +442,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -3931,6 +3933,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.49.0 + diff --git a/patches/6.15/0004-ath10k.patch b/patches/6.15/0004-ath10k.patch new file mode 100644 index 0000000000..e50e6c5b27 --- /dev/null +++ b/patches/6.15/0004-ath10k.patch @@ -0,0 +1,120 @@ +From bb582f0942d5b505c0c2744c5a24e1711ae9ce8f Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index b3294287bce1..2936fdae823c 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.49.0 + diff --git a/patches/6.15/0005-ipts.patch b/patches/6.15/0005-ipts.patch new file mode 100644 index 0000000000..7519047a5e --- /dev/null +++ b/patches/6.15/0005-ipts.patch @@ -0,0 +1,3243 @@ +From b89f20bfa13868323f9875acfe07e9d8f618329f Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index a5f88ec97df7..e379dc2373b5 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index d6ff9d82ae94..a1b714505f43 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.49.0 + +From 8690c582cf49e817cff1f4ff216c4c1828682c78 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 25d31f8c129a..3735ed60032d 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -39,6 +39,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -207,12 +212,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -1902,6 +1909,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2196,6 +2206,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4493,6 +4506,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4528,6 +4553,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.49.0 + +From 458d45bfbecaad616ed515d82abe8598fe8c2b0e Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index dfc245867a46..f91ba8a06cfc 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1387,6 +1387,8 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 0abfe51704a0..c86c9e80d225 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -172,3 +172,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.49.0 + diff --git a/patches/6.15/0006-ithc.patch b/patches/6.15/0006-ithc.patch new file mode 100644 index 0000000000..f3e96a5669 --- /dev/null +++ b/patches/6.15/0006-ithc.patch @@ -0,0 +1,2773 @@ +From 85f3a4111005d23749f1a5b0424264ba38bbb3f4 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index ad795c772f21..2c10bca9e06b 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -388,6 +388,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.49.0 + +From 3e386a2ed36c9d620f4de23d671daa75a509d797 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2568 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index f91ba8a06cfc..e945736e216f 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1389,6 +1389,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index c86c9e80d225..046eb5fd8017 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -174,3 +174,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { ++ .vendor = PCI_VENDOR_ID_INTEL, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = PCI_CLASS_INPUT_PEN << 8, ++ .class_mask = ~0, ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.49.0 + diff --git a/patches/6.15/0007-surface-sam.patch b/patches/6.15/0007-surface-sam.patch new file mode 100644 index 0000000000..a4d7a23739 --- /dev/null +++ b/patches/6.15/0007-surface-sam.patch @@ -0,0 +1,211 @@ +From 156b853c039f830407bea29f01bb6f3489c7c3e1 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 17 Jun 2022 02:14:00 +0200 +Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator + Module + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/rtc/Kconfig | 7 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 drivers/rtc/rtc-surface.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 0bbbf778ecfa..bd1d5c0dd6df 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1383,6 +1383,13 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_SURFACE ++ tristate "Microsoft Surface Aggregator RTC" ++ depends on SURFACE_AGGREGATOR ++ depends on SURFACE_AGGREGATOR_BUS ++ help ++ TODO ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 489b4ab07068..061afa9db5b6 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -180,6 +180,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o + obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o + obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o + obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o ++obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o +diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c +new file mode 100644 +index 000000000000..f6c17c4e98d5 +--- /dev/null ++++ b/drivers/rtc/rtc-surface.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * AC driver for 7th-generation Microsoft Surface devices via Surface System ++ * Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2019-2021 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct surface_rtc { ++ struct ssam_device *sdev; ++ struct rtc_device *rtc; ++}; ++ ++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x10, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x0f, ++}); ++ ++static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) ++{ ++ __le32 time_le; ++ int status; ++ ++ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); ++ if (status) ++ return status; ++ ++ *time = le32_to_cpu(time_le); ++ return 0; ++} ++ ++static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) ++{ ++ __le32 time_le = cpu_to_le32(time); ++ ++ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); ++} ++ ++static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ int status; ++ u32 time; ++ ++ status = ssam_rtc_get_unix_time(srtc, &time); ++ if (status) ++ return status; ++ ++ rtc_time64_to_tm(time, tm); ++ return 0; ++} ++ ++static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ time64_t time = rtc_tm_to_time64(tm); ++ ++ return ssam_rtc_set_unix_time(srtc, (u32)time); ++} ++ ++static const struct rtc_class_ops surface_rtc_ops = { ++ .read_time = surface_rtc_read_time, ++ .set_time = surface_rtc_set_time, ++}; ++ ++static int surface_rtc_probe(struct ssam_device *sdev) ++{ ++ struct surface_rtc *srtc; ++ ++ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->sdev = sdev; ++ ++ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); ++ if (IS_ERR(srtc->rtc)) ++ return PTR_ERR(srtc->rtc); ++ ++ srtc->rtc->ops = &surface_rtc_ops; ++ srtc->rtc->range_max = U32_MAX; ++ ++ ssam_device_set_drvdata(sdev, srtc); ++ ++ return devm_rtc_register_device(srtc->rtc); ++} ++ ++static void surface_rtc_remove(struct ssam_device *sdev) ++{ ++ /* Device-managed allocations take care of everything... */ ++} ++ ++static const struct ssam_device_id surface_rtc_match[] = { ++ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, surface_rtc_match); ++ ++static struct ssam_device_driver surface_rtc_driver = { ++ .probe = surface_rtc_probe, ++ .remove = surface_rtc_remove, ++ .match_table = surface_rtc_match, ++ .driver = { ++ .name = "surface_rtc", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(surface_rtc_driver); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.49.0 + +From 3dec366702ebcfb04f7805144eca4c943d19802b Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 20 Apr 2025 01:05:14 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 + (ACPI) + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index a594d5fcfcfd..07b03aa4fa7f 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Laptop 6 */ + { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + ++ /* Surface Laptop 7 */ ++ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.49.0 + diff --git a/patches/6.15/0008-surface-sam-over-hid.patch b/patches/6.15/0008-surface-sam-over-hid.patch new file mode 100644 index 0000000000..293932558f --- /dev/null +++ b/patches/6.15/0008-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From b0c24f19804345b57672cf54e5caa7ba473f3f26 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index d2499f302b50..77ce5ec3dd9e 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -661,6 +661,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -762,6 +783,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.49.0 + +From b27002518a3b386bc3c2d50d7e45c94148375aa4 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af97c..68656e8f309e 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.49.0 + diff --git a/patches/6.15/0009-surface-button.patch b/patches/6.15/0009-surface-button.patch new file mode 100644 index 0000000000..c0676281f3 --- /dev/null +++ b/patches/6.15/0009-surface-button.patch @@ -0,0 +1,149 @@ +From 3e79d7b95f28bfcd981ca7db961407b2375307be Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index b8cad415c62c..43b5d56383e3 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.49.0 + +From 8cbc63032afb8606805a14cc1c5f29d9105567c0 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.49.0 + diff --git a/patches/6.15/0010-surface-typecover.patch b/patches/6.15/0010-surface-typecover.patch new file mode 100644 index 0000000000..f6cb483ced --- /dev/null +++ b/patches/6.15/0010-surface-typecover.patch @@ -0,0 +1,235 @@ +From 76accddaf1b7b28acb671305efb2a71eee0ea4af Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e50887a6d22c..4ce18f21a141 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -35,7 +35,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -73,12 +77,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -176,6 +183,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -220,6 +229,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -410,6 +420,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1759,6 +1779,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1782,6 +1865,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1820,8 +1906,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); +@@ -1830,8 +1918,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1881,7 +1971,8 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); + hid_hw_stop(hdev); +@@ -2304,6 +2395,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.49.0 \ No newline at end of file diff --git a/patches/6.15/0011-surface-shutdown.patch b/patches/6.15/0011-surface-shutdown.patch new file mode 100644 index 0000000000..78f51d0046 --- /dev/null +++ b/patches/6.15/0011-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 26f09bed8d9daf48f62882e9e0307f2c81130870 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index f57ea36d125d..cdb74ec6c082 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 82b21e34c545..ccf29cfa7082 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6316,3 +6316,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 47b31ad724fa..c571fdca6c5f 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -476,6 +476,7 @@ struct pci_dev { + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ +-- +2.49.0 + diff --git a/patches/6.15/0012-surface-gpe.patch b/patches/6.15/0012-surface-gpe.patch new file mode 100644 index 0000000000..605d05eba6 --- /dev/null +++ b/patches/6.15/0012-surface-gpe.patch @@ -0,0 +1,51 @@ +From 0ea6591811ba84ac67dc7bb320d2048e949f7aad Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index b359413903b1..b4496db79f39 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.49.0 + diff --git a/patches/6.15/0013-cameras.patch b/patches/6.15/0013-cameras.patch new file mode 100644 index 0000000000..796f9342c3 --- /dev/null +++ b/patches/6.15/0013-cameras.patch @@ -0,0 +1,743 @@ +From 8678f0c1ed1a9d4f5cad1e0c0c677630a242d4bd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 9f4efa8f75a6..7c7ef03cafa4 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2204,6 +2204,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.49.0 + +From 069b8c0dd7460410d2e4d333bc533221d709cb17 Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 3735ed60032d..71cccee6e4a9 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -44,6 +44,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -213,12 +220,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -1910,6 +1919,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2206,6 +2218,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4506,6 +4521,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4553,6 +4580,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.49.0 + +From 5bc57f06d3dc085a2a0757fc5c35be36c2d6d341 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 81ac4c691963..f453c9043042 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.49.0 + +From c7a4afe01bfd24fbfc3735d1b60f08be3aef0b81 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Thu, 2 Mar 2023 12:59:39 +0000 +Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E + +ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The +driver for this sensor expects a single pin named "enable", but on +some Microsoft Surface platforms the sensor is assigned a single +GPIO who's type flag is INT3472_GPIO_TYPE_RESET. + +Remap the GPIO pin's function from "reset" to "enable". This is done +outside of the existing remap table since it is a more widespread +discrepancy than that method is designed for. Additionally swap the +polarity of the pin to match the driver's expectation. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 092252eb95a8..7a73d5f903a9 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -81,18 +81,33 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472, + struct acpi_resource_gpio *agpio, + const char *con_id, unsigned long gpio_flags) + { + int ret; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ { } ++ }; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ gpio_flags ^= GPIO_ACTIVE_LOW; ++ } ++ + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, con_id, gpio_flags); + if (ret) + return ret; + + int3472->n_sensor_gpios++; + + return 0; +-- +2.49.0 + +From 9ab2f02228baf5661844d4ba55810273b75cb456 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 30f61e04ecaf..9c1292ca8552 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.49.0 + +From 4cfbc183671a5e27fb1808a0489dc4053ff970aa Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index cb153ce42c45..f11b499e14bb 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.49.0 + +From 6bede17be7b28d507138775eda22c15c020ee22d Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index f453c9043042..b8ad6b413e8b 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.49.0 + +From 4b91d36e045045a2f5029a47b33984c33a1d58cf Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.49.0 + +From 4606e818fd812630708c340acdc7a493d703842d Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 2b27d043921c..22a8c20de32a 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -985,6 +985,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 6ad52e219ec6..3519b4c32c9e 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -91,6 +91,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_UPBOARD) += leds-upboard.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.49.0 + +From 2666871d2780d86053ac2d61350de05de6888204 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928..0094cfda57ea 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -82,9 +82,12 @@ static int dw9719_power_up(struct dw9719_device *dw9719) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); + fsleep(100); + cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_STANDBY, &ret); + /* Need 100us to transit from SHUTDOWN to STANDBY */ + fsleep(100); +-- +2.49.0 + diff --git a/patches/6.15/0014-amd-gpio.patch b/patches/6.15/0014-amd-gpio.patch new file mode 100644 index 0000000000..10af4fc612 --- /dev/null +++ b/patches/6.15/0014-amd-gpio.patch @@ -0,0 +1,108 @@ +From dc693e53aeaa7bcfea526f8867a3c2c3d027e7ef Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index dae6a73be40e..f401a6676b5e 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,5 +22,6 @@ + #include + #include + #include ++#include + + #include +@@ -1169,6 +1170,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1225,6 +1237,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.49.0 + +From 61a2673dc1feba27dea028f0e373081a19f3b6f6 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index f401a6676b5e..fe3df37bfaff 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1172,12 +1172,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.49.0 + diff --git a/patches/6.15/0015-rtc.patch b/patches/6.15/0015-rtc.patch new file mode 100644 index 0000000000..a46655ddf9 --- /dev/null +++ b/patches/6.15/0015-rtc.patch @@ -0,0 +1,110 @@ +From 15bf9fcbacae64d8a208be07828b4aa7ae031482 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 825c2a8acea4..74612088ac5f 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.49.0 + From 9bc701928ccbc5f8ddf406b5673d2b1df3dbcc04 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 21 Jun 2025 22:46:56 +0200 Subject: [PATCH 105/236] Remove old fedora-specific patches --- patches/6.13-fedora/0001-secureboot.patch | 112 - patches/6.13-fedora/0002-surface3.patch | 234 -- patches/6.13-fedora/0003-mwifiex.patch | 400 -- patches/6.13-fedora/0004-ath10k.patch | 120 - patches/6.13-fedora/0005-ipts.patch | 3241 ----------------- patches/6.13-fedora/0006-ithc.patch | 2771 -------------- patches/6.13-fedora/0007-surface-sam.patch | 211 -- .../0008-surface-sam-over-hid.patch | 308 -- patches/6.13-fedora/0009-surface-button.patch | 149 - .../6.13-fedora/0010-surface-typecover.patch | 575 --- .../6.13-fedora/0011-surface-shutdown.patch | 97 - patches/6.13-fedora/0012-surface-gpe.patch | 51 - patches/6.13-fedora/0013-cameras.patch | 734 ---- patches/6.13-fedora/0014-amd-gpio.patch | 109 - patches/6.13-fedora/0015-rtc.patch | 110 - 15 files changed, 9222 deletions(-) delete mode 100644 patches/6.13-fedora/0001-secureboot.patch delete mode 100644 patches/6.13-fedora/0002-surface3.patch delete mode 100644 patches/6.13-fedora/0003-mwifiex.patch delete mode 100644 patches/6.13-fedora/0004-ath10k.patch delete mode 100644 patches/6.13-fedora/0005-ipts.patch delete mode 100644 patches/6.13-fedora/0006-ithc.patch delete mode 100644 patches/6.13-fedora/0007-surface-sam.patch delete mode 100644 patches/6.13-fedora/0008-surface-sam-over-hid.patch delete mode 100644 patches/6.13-fedora/0009-surface-button.patch delete mode 100644 patches/6.13-fedora/0010-surface-typecover.patch delete mode 100644 patches/6.13-fedora/0011-surface-shutdown.patch delete mode 100644 patches/6.13-fedora/0012-surface-gpe.patch delete mode 100644 patches/6.13-fedora/0013-cameras.patch delete mode 100644 patches/6.13-fedora/0014-amd-gpio.patch delete mode 100644 patches/6.13-fedora/0015-rtc.patch diff --git a/patches/6.13-fedora/0001-secureboot.patch b/patches/6.13-fedora/0001-secureboot.patch deleted file mode 100644 index c77b88a14e..0000000000 --- a/patches/6.13-fedora/0001-secureboot.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 7c9810fb3e614eba177052a3d4ed949de0c1a75e Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 9 Jun 2024 19:48:58 +0200 -Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag - unconditionally" - -This reverts commit 891f8890a4a3663da7056542757022870b499bc1. - -Revert because of compatibility issues of MS Surface devices and GRUB -with NX. In short, these devices get stuck on boot with NX advertised. -So to not advertise it, add the respective option back in. - -Signed-off-by: Maximilian Luz -Patchset: secureboot ---- - arch/x86/boot/header.S | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index b5c79f43359b..a1bbedd989e4 100644 ---- a/arch/x86/boot/header.S -+++ b/arch/x86/boot/header.S -@@ -111,7 +111,11 @@ extra_header_fields: - .long salign # SizeOfHeaders - .long 0 # CheckSum - .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) -+#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES - .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics -+#else -+ .word 0 # DllCharacteristics -+#endif - #ifdef CONFIG_X86_32 - .long 0 # SizeOfStackReserve - .long 0 # SizeOfStackCommit --- -2.49.0 - -From 6ff310318f3a73e852625038b146dabe81501c34 Mon Sep 17 00:00:00 2001 -From: "J. Eduardo" -Date: Sun, 25 Aug 2024 14:17:45 +0200 -Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter - -This allows the user to tell the kernel that they know better (namely, -they secured their swap properly), and that it can enable hibernation. - -Signed-off-by: Kelvie Wong -Link: https://github.com/linux-surface/kernel/pull/158 -Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee -Patchset: secureboot ---- - Documentation/admin-guide/kernel-parameters.txt | 5 +++++ - kernel/power/hibernate.c | 10 +++++++++- - 2 files changed, 14 insertions(+), 1 deletion(-) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 3872bc6ec49d..e322b97879c2 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3074,6 +3074,11 @@ - to extract confidential information from the kernel - are also disabled. - -+ lockdown_hibernate [HIBERNATION] -+ Enable hibernation even if lockdown is enabled. Enable this only if -+ your swap is encrypted and secured properly, as an attacker can -+ modify the kernel offline during hibernation. -+ - locktorture.acq_writer_lim= [KNL] - Set the time limit in jiffies for a lock - acquisition. Acquisitions exceeding this limit -diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 10a01af63a80..e53e4a86e4cc 100644 ---- a/kernel/power/hibernate.c -+++ b/kernel/power/hibernate.c -@@ -37,6 +37,7 @@ - #include "power.h" - - -+static int lockdown_hibernate; - static int nocompress; - static int noresume; - static int nohibernate; -@@ -92,7 +93,7 @@ void hibernate_release(void) - bool hibernation_available(void) - { - return nohibernate == 0 && -- !security_locked_down(LOCKDOWN_HIBERNATION) && -+ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && - !secretmem_active() && !cxl_mem_active(); - } - -@@ -1434,6 +1435,12 @@ static int __init nohibernate_setup(char *str) - return 1; - } - -+static int __init lockdown_hibernate_setup(char *str) -+{ -+ lockdown_hibernate = 1; -+ return 1; -+} -+ - static const char * const comp_alg_enabled[] = { - #if IS_ENABLED(CONFIG_CRYPTO_LZO) - COMPRESSION_ALGO_LZO, -@@ -1492,3 +1499,4 @@ __setup("hibernate=", hibernate_setup); - __setup("resumewait", resumewait_setup); - __setup("resumedelay=", resumedelay_setup); - __setup("nohibernate", nohibernate_setup); -+__setup("lockdown_hibernate", lockdown_hibernate_setup); --- -2.49.0 - diff --git a/patches/6.13-fedora/0002-surface3.patch b/patches/6.13-fedora/0002-surface3.patch deleted file mode 100644 index eb7cff72c4..0000000000 --- a/patches/6.13-fedora/0002-surface3.patch +++ /dev/null @@ -1,234 +0,0 @@ -From 481ba7958a7d0ae882d6a4ccbf47fa326acde51c Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 18 Oct 2020 16:42:44 +0900 -Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI - table - -On some Surface 3, the DMI table gets corrupted for unknown reasons -and breaks existing DMI matching used for device-specific quirks. - -This commit adds the (broken) DMI data into dmi_system_id tables used -for quirks so that each driver can enable quirks even on the affected -systems. - -On affected systems, DMI data will look like this: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:OEMB - /sys/devices/virtual/dmi/id/board_vendor:OEMB - /sys/devices/virtual/dmi/id/chassis_vendor:OEMB - /sys/devices/virtual/dmi/id/product_name:OEMB - /sys/devices/virtual/dmi/id/sys_vendor:OEMB - -Expected: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:Surface 3 - /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/product_name:Surface 3 - /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation - -Signed-off-by: Tsuchiya Yuto -Patchset: surface3 ---- - drivers/platform/surface/surface3-wmi.c | 7 +++++++ - sound/soc/codecs/rt5645.c | 9 +++++++++ - sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ - 3 files changed, 24 insertions(+) - -diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index 6c8fb7a4dde4..22797a53f4d8 100644 ---- a/drivers/platform/surface/surface3-wmi.c -+++ b/drivers/platform/surface/surface3-wmi.c -@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - #endif - { } - }; -diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 51187b1e0ed2..bfb83ce8d8f8 100644 ---- a/sound/soc/codecs/rt5645.c -+++ b/sound/soc/codecs/rt5645.c -@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { - }, - .driver_data = (void *)&intel_braswell_platform_data, - }, -+ { -+ .ident = "Microsoft Surface 3", -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ .driver_data = (void *)&intel_braswell_platform_data, -+ }, - { - /* - * Match for the GPDwin which unfortunately uses somewhat -diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0c28..0b930c91bccb 100644 ---- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .callback = cht_surface_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - { } - }; - --- -2.49.0 - -From 2e5a1e90796ecbf74d851f179aeebd327da00f07 Mon Sep 17 00:00:00 2001 -From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> -Date: Fri, 6 Dec 2019 23:10:30 +0900 -Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by - default - -On Arch Linux kernel at least after 4.19, touch input is broken after suspend -(s2idle). - - kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out - -On recent stable Arch Linux kernel (at least after 5.1), touch input will -crash after the first touch. - - kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out - kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue - -I found on an affected system (Arch Linux kernel, etc.), the touchscreen -driver uses DMA mode by default. Then, we found some kernels with different -kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel -chromeos-4.19 [2]) will use PIO mode by default and no such issues there. - -So, this commit disables DMA mode on the touchscreen driver side as a quick -workaround to avoid touch input crash. -We may need to properly set up DMA mode to use the touchscreen driver with -DMA mode. - -You can still switch DMA/PIO mode if you want: - - switch to DMA mode (maybe broken) - echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma - back to PIO mode - echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma - -Link to issue: https://github.com/jakeday/linux-surface/issues/596 - -References: -[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config -[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 - -Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. -This commit made the driver use PIO by default and no touch input crash. -Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default -even without this commit. After this commit, it still uses PIO and confirmed -no functional changes regarding touch input. - -More details: - We can confirm which mode the touchscreen driver uses; first, enable - debug output: - - echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control - echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control - - Then, try to make a touch input and see dmesg log - - (On Arch Linux kernel, uses DMA) - kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA - kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received - -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 - c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - - (On the kernels I referenced above, uses PIO) - kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO - kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received - -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 - 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - -Note (2025-03-08): This patch was originally dropped due to the -comments in [3]. However, according to the commments in [4] it is still -required. - -[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a -[4]: https://github.com/linux-surface/linux-surface/issues/1184 - -Patchset: surface3 ---- - drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ - 1 file changed, 26 insertions(+) - -diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c -index 6074b7730e86..6aa3e1d6f160 100644 ---- a/drivers/input/touchscreen/surface3_spi.c -+++ b/drivers/input/touchscreen/surface3_spi.c -@@ -25,6 +25,12 @@ - #define SURFACE3_REPORT_TOUCH 0xd2 - #define SURFACE3_REPORT_PEN 0x16 - -+bool use_dma = false; -+module_param(use_dma, bool, 0644); -+MODULE_PARM_DESC(use_dma, -+ "Disable DMA mode if you encounter touch input crash. " -+ "(default: false, disabled to avoid crash)"); -+ - struct surface3_ts_data { - struct spi_device *spi; - struct gpio_desc *gpiod_rst[2]; -@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) - return 0; - } - -+static bool surface3_spi_can_dma(struct spi_controller *ctlr, -+ struct spi_device *spi, -+ struct spi_transfer *tfr) -+{ -+ return use_dma; -+} -+ - static int surface3_spi_probe(struct spi_device *spi) - { - struct surface3_ts_data *data; -@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) - if (error) - return error; - -+ /* -+ * Set up DMA -+ * -+ * TODO: Currently, touch input with DMA seems to be broken. -+ * On 4.19 LTS, touch input will crash after suspend. -+ * On recent stable kernel (at least after 5.1), touch input will crash after -+ * the first touch. No problem with PIO on those kernels. -+ * Maybe we need to configure DMA here. -+ * -+ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 -+ */ -+ spi->controller->can_dma = surface3_spi_can_dma; -+ - return 0; - } - --- -2.49.0 - diff --git a/patches/6.13-fedora/0003-mwifiex.patch b/patches/6.13-fedora/0003-mwifiex.patch deleted file mode 100644 index 8f2988bf82..0000000000 --- a/patches/6.13-fedora/0003-mwifiex.patch +++ /dev/null @@ -1,400 +0,0 @@ -From c4e6fa29a9f4a4a09a618574a8ecf7efa1e051fd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Tue, 3 Nov 2020 13:28:04 +0100 -Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface - devices - -The most recent firmware of the 88W8897 card reports a hardcoded LTR -value to the system during initialization, probably as an (unsuccessful) -attempt of the developers to fix firmware crashes. This LTR value -prevents most of the Microsoft Surface devices from entering deep -powersaving states (either platform C-State 10 or S0ix state), because -the exit latency of that state would be higher than what the card can -tolerate. - -Turns out the card works just the same (including the firmware crashes) -no matter if that hardcoded LTR value is reported or not, so it's kind -of useless and only prevents us from saving power. - -To get rid of those hardcoded LTR reports, it's possible to reset the -PCI bridge device after initializing the cards firmware. I'm not exactly -sure why that works, maybe the power management subsystem of the PCH -resets its stored LTR values when doing a function level reset of the -bridge device. Doing the reset once after starting the wifi firmware -works very well, probably because the firmware only reports that LTR -value a single time during firmware startup. - -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 3 files changed, 31 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 5f997becdbaa..9a9929424513 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) - static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) - { - struct pcie_service_card *card = adapter->card; -+ struct pci_dev *pdev = card->dev; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; - -+ /* Trigger a function level reset of the PCI bridge device, this makes -+ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value -+ * that prevents the system from entering package C10 and S0ix powersaving -+ * states. -+ * We need to do it here because it must happen after firmware -+ * initialization and this function is called after that is done. -+ */ -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ pci_reset_function(parent_pdev); -+ - /* Write the RX ring read pointer in to reg->rx_rdptr */ - mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); - } -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5", -@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 6", -@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 1", -@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 2", -@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 1", -@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 2", -@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - {} - }; -@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "no quirks enabled\n"); - if (card->quirks & QUIRK_FW_RST_D3COLD) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); - } - - static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -4,6 +4,7 @@ - #include "pcie.h" - - #define QUIRK_FW_RST_D3COLD BIT(0) -+#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) - - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.49.0 - -From 1b3a3a96870f12d3d7001335039530e93b8bac36 Mon Sep 17 00:00:00 2001 -From: Tsuchiya Yuto -Date: Sun, 4 Oct 2020 00:11:49 +0900 -Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ - -Currently, mwifiex fw will crash after suspend on recent kernel series. -On Windows, it seems that the root port of wifi will never enter D3 state -(stay on D0 state). And on Linux, disabling the D3 state for the -bridge fixes fw crashing after suspend. - -This commit disables the D3 state of root port on driver initialization -and fixes fw crashing after suspend. - -Signed-off-by: Tsuchiya Yuto -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 3 files changed, 27 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 9a9929424513..2273e3029776 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) - { - struct pcie_service_card *card; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - int ret; - - pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", -@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - return -1; - } - -+ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing -+ * after suspend -+ */ -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ parent_pdev->bridge_d3 = false; -+ - return 0; - } - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5", -@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 6", -@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 1", -@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 2", -@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 1", -@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 2", -@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - {} - }; -@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); - if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) - dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ dev_info(&pdev->dev, -+ "quirk no_brigde_d3 enabled\n"); - } - - static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -5,6 +5,7 @@ - - #define QUIRK_FW_RST_D3COLD BIT(0) - #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) -+#define QUIRK_NO_BRIDGE_D3 BIT(2) - - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.49.0 - -From 517f11111b957f8e90dc9488a6bad4faf0fcec88 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 25 Mar 2021 11:33:02 +0100 -Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell - 88W8897 - -The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) -is used in a lot of Microsoft Surface devices, and all those devices -suffer from very low 2.4GHz wifi connection speeds while bluetooth is -enabled. The reason for that is that the default passive scanning -interval for Bluetooth Low Energy devices is quite high in Linux -(interval of 60 msec and scan window of 30 msec, see hci_core.c), and -the Marvell chip is known for its bad bt+wifi coexisting performance. - -So decrease that passive scan interval and make the scan window shorter -on this particular device to allow for spending more time transmitting -wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and -the new scan window is 6.25 msec (0xa * 0,625 msec). - -This change has a very large impact on the 2.4GHz wifi speeds and gets -it up to performance comparable with the Windows driver, which seems to -apply a similar quirk. - -The interval and window length were tested and found to work very well -with a lot of Bluetooth Low Energy devices, including the Surface Pen, a -Bluetooth Speaker and two modern Bluetooth headphones. All devices were -discovered immediately after turning them on. Even lower values were -also tested, but they introduced longer delays until devices get -discovered. - -Patchset: mwifiex ---- - drivers/bluetooth/btusb.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 75dbe07e07e2..fd0f1aa5eaa9 100644 ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; - #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) - #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) - #define BTUSB_ACTIONS_SEMI BIT(27) -+#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) - - static const struct usb_device_id btusb_table[] = { - /* Generic Bluetooth USB device */ -@@ -440,6 +441,7 @@ static const struct usb_device_id quirks_table[] = { - { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, - { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, - { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, -+ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, - - /* Intel Bluetooth devices */ - { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3870,6 +3872,19 @@ static int btusb_probe(struct usb_interface *intf, - if (id->driver_info & BTUSB_MARVELL) - hdev->set_bdaddr = btusb_set_bdaddr_marvell; - -+ /* The Marvell 88W8897 combined wifi and bluetooth card is known for -+ * very bad bt+wifi coexisting performance. -+ * -+ * Decrease the passive BT Low Energy scan interval a bit -+ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter -+ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly -+ * higher wifi throughput while passively scanning for BT LE devices. -+ */ -+ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { -+ hdev->le_scan_interval = 0x0190; -+ hdev->le_scan_window = 0x000a; -+ } -+ - if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && - (id->driver_info & BTUSB_MEDIATEK)) { - hdev->setup = btusb_mtk_setup; --- -2.49.0 - diff --git a/patches/6.13-fedora/0004-ath10k.patch b/patches/6.13-fedora/0004-ath10k.patch deleted file mode 100644 index 67a4c54358..0000000000 --- a/patches/6.13-fedora/0004-ath10k.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 139fca7bcfd8aaa876636ff7c50f319028027073 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 27 Feb 2021 00:45:52 +0100 -Subject: [PATCH] ath10k: Add module parameters to override board files - -Some Surface devices, specifically the Surface Go and AMD version of the -Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better -with a different board file, as it seems that the firmeware included -upstream is buggy. - -As it is generally not a good idea to randomly overwrite files, let -alone doing so via packages, we add module parameters to override those -file names in the driver. This allows us to package/deploy the override -via a modprobe.d config. - -Signed-off-by: Maximilian Luz -Patchset: ath10k ---- - drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ - 1 file changed, 57 insertions(+) - -diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index b3294287bce1..2936fdae823c 100644 ---- a/drivers/net/wireless/ath/ath10k/core.c -+++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -40,6 +40,9 @@ static bool fw_diag_log; - /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ - unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; - -+static char *override_board = ""; -+static char *override_board2 = ""; -+ - unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | - BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); - -@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); - module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); - module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); - -+module_param(override_board, charp, 0644); -+module_param(override_board2, charp, 0644); -+ - MODULE_PARM_DESC(debug_mask, "Debugging mask"); - MODULE_PARM_DESC(uart_print, "Uart target debugging"); - MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); -@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, - MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); - MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); - -+MODULE_PARM_DESC(override_board, "Override for board.bin file"); -+MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); -+ - static const struct ath10k_hw_params ath10k_hw_params_list[] = { - { - .id = QCA988X_HW_2_0_VERSION, -@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) - return 0; - } - -+static const char *ath10k_override_board_fw_file(struct ath10k *ar, -+ const char *file) -+{ -+ if (strcmp(file, "board.bin") == 0) { -+ if (strcmp(override_board, "") == 0) -+ return file; -+ -+ if (strcmp(override_board, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); -+ return NULL; -+ } -+ -+ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", -+ override_board); -+ -+ return override_board; -+ } -+ -+ if (strcmp(file, "board-2.bin") == 0) { -+ if (strcmp(override_board2, "") == 0) -+ return file; -+ -+ if (strcmp(override_board2, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); -+ return NULL; -+ } -+ -+ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", -+ override_board2); -+ -+ return override_board2; -+ } -+ -+ return file; -+} -+ - static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - const char *dir, - const char *file) -@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - if (dir == NULL) - dir = "."; - -+ /* HACK: Override board.bin and board-2.bin files if specified. -+ * -+ * Some Surface devices perform better with a different board -+ * configuration. To this end, one would need to replace the board.bin -+ * file with the modified config and remove the board-2.bin file. -+ * Unfortunately, that's not a solution that we can easily package. So -+ * we add module options to perform these overrides here. -+ */ -+ file = ath10k_override_board_fw_file(ar, file); -+ if (!file) -+ return ERR_PTR(-ENOENT); -+ - if (ar->board_name) { - snprintf(filename, sizeof(filename), "%s/%s/%s", - dir, ar->board_name, file); --- -2.49.0 - diff --git a/patches/6.13-fedora/0005-ipts.patch b/patches/6.13-fedora/0005-ipts.patch deleted file mode 100644 index 0529507211..0000000000 --- a/patches/6.13-fedora/0005-ipts.patch +++ /dev/null @@ -1,3241 +0,0 @@ -From a7b5a85b385d7beabbb4f01f8bd2bcfcfcdffb4e Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Thu, 30 Jul 2020 13:21:53 +0200 -Subject: [PATCH] mei: me: Add Icelake device ID for iTouch - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/misc/mei/hw-me-regs.h | 1 + - drivers/misc/mei/pci-me.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index a5f88ec97df7..e379dc2373b5 100644 ---- a/drivers/misc/mei/hw-me-regs.h -+++ b/drivers/misc/mei/hw-me-regs.h -@@ -92,6 +92,7 @@ - #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ - - #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ -+#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ - #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ - - #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ -diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index d6ff9d82ae94..a1b714505f43 100644 ---- a/drivers/misc/mei/pci-me.c -+++ b/drivers/misc/mei/pci-me.c -@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { - {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, -+ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, --- -2.49.0 - -From 139a811cea8c408bc37e58b26cd593853f3efa64 Mon Sep 17 00:00:00 2001 -From: Liban Hannan -Date: Tue, 12 Apr 2022 23:31:12 +0100 -Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS - -Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. -Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: - -DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr -0x104ea3000 [fault reason 0x06] PTE Read access is not set - -This is very similar to the bug described at: -https://bugs.launchpad.net/bugs/1958004 - -Fixed with the following patch which this patch basically copies: -https://launchpadlibrarian.net/586396847/43255ca.diff - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 9ab5371c3538..1839a831a89f 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -40,6 +40,11 @@ - #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) - #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) - -+#define IS_IPTS(pdev) ( \ -+ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ -+ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ -+ ) -+ - #define IOAPIC_RANGE_START (0xfee00000) - #define IOAPIC_RANGE_END (0xfeefffff) - #define IOVA_START_ADDR (0x1000) -@@ -208,12 +213,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); - int intel_iommu_enabled = 0; - EXPORT_SYMBOL_GPL(intel_iommu_enabled); - -+static int dmar_map_ipts = 1; - static int intel_iommu_superpage = 1; - static int iommu_identity_mapping; - static int iommu_skip_te_disable; - static int disable_igfx_iommu; - - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPTS 16 - - const struct iommu_ops intel_iommu_ops; - static const struct iommu_dirty_ops intel_dirty_ops; -@@ -1903,6 +1910,9 @@ static int device_def_domain_type(struct device *dev) - - if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) - return IOMMU_DOMAIN_IDENTITY; -+ -+ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; - } - - return 0; -@@ -2201,6 +2211,9 @@ static int __init init_dmars(void) - iommu_set_root_entry(iommu); - } - -+ if (!dmar_map_ipts) -+ iommu_identity_mapping |= IDENTMAP_IPTS; -+ - check_tylersburg_isoch(); - - /* -@@ -4509,6 +4522,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - disable_igfx_iommu = 1; - } - -+static void quirk_iommu_ipts(struct pci_dev *dev) -+{ -+ if (!IS_IPTS(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; -+ -+ pci_info(dev, "Disabling IOMMU for IPTS\n"); -+ dmar_map_ipts = 0; -+} -+ - /* G4x/GM45 integrated gfx dmar support is totally busted. */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4544,6 +4569,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); - -+/* disable IPTS dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -+ - static void quirk_iommu_rwbf(struct pci_dev *dev) - { - if (risky_device(dev)) --- -2.49.0 - -From 7e49c5f2dce59ad34df0a3a9d01d17bf2e30771f Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Sun, 11 Dec 2022 12:00:59 +0100 -Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus - -Based on linux-surface/intel-precise-touch@8abe268 - -Signed-off-by: Dorian Stoll -Patchset: ipts ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 2 + - drivers/hid/ipts/Kconfig | 14 + - drivers/hid/ipts/Makefile | 16 ++ - drivers/hid/ipts/cmd.c | 61 +++++ - drivers/hid/ipts/cmd.h | 60 ++++ - drivers/hid/ipts/context.h | 52 ++++ - drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ - drivers/hid/ipts/control.h | 126 +++++++++ - drivers/hid/ipts/desc.h | 80 ++++++ - drivers/hid/ipts/eds1.c | 104 +++++++ - drivers/hid/ipts/eds1.h | 35 +++ - drivers/hid/ipts/eds2.c | 145 ++++++++++ - drivers/hid/ipts/eds2.h | 35 +++ - drivers/hid/ipts/hid.c | 225 +++++++++++++++ - drivers/hid/ipts/hid.h | 24 ++ - drivers/hid/ipts/main.c | 126 +++++++++ - drivers/hid/ipts/mei.c | 188 +++++++++++++ - drivers/hid/ipts/mei.h | 66 +++++ - drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ - drivers/hid/ipts/receiver.h | 16 ++ - drivers/hid/ipts/resources.c | 131 +++++++++ - drivers/hid/ipts/resources.h | 41 +++ - drivers/hid/ipts/spec-data.h | 100 +++++++ - drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ - drivers/hid/ipts/spec-hid.h | 34 +++ - drivers/hid/ipts/thread.c | 84 ++++++ - drivers/hid/ipts/thread.h | 59 ++++ - 28 files changed, 2853 insertions(+) - create mode 100644 drivers/hid/ipts/Kconfig - create mode 100644 drivers/hid/ipts/Makefile - create mode 100644 drivers/hid/ipts/cmd.c - create mode 100644 drivers/hid/ipts/cmd.h - create mode 100644 drivers/hid/ipts/context.h - create mode 100644 drivers/hid/ipts/control.c - create mode 100644 drivers/hid/ipts/control.h - create mode 100644 drivers/hid/ipts/desc.h - create mode 100644 drivers/hid/ipts/eds1.c - create mode 100644 drivers/hid/ipts/eds1.h - create mode 100644 drivers/hid/ipts/eds2.c - create mode 100644 drivers/hid/ipts/eds2.h - create mode 100644 drivers/hid/ipts/hid.c - create mode 100644 drivers/hid/ipts/hid.h - create mode 100644 drivers/hid/ipts/main.c - create mode 100644 drivers/hid/ipts/mei.c - create mode 100644 drivers/hid/ipts/mei.h - create mode 100644 drivers/hid/ipts/receiver.c - create mode 100644 drivers/hid/ipts/receiver.h - create mode 100644 drivers/hid/ipts/resources.c - create mode 100644 drivers/hid/ipts/resources.h - create mode 100644 drivers/hid/ipts/spec-data.h - create mode 100644 drivers/hid/ipts/spec-device.h - create mode 100644 drivers/hid/ipts/spec-hid.h - create mode 100644 drivers/hid/ipts/thread.c - create mode 100644 drivers/hid/ipts/thread.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index b7e010c384ba..d36a55e58598 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1389,4 +1389,6 @@ source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/intel-thc-hid/Kconfig" - -+source "drivers/hid/ipts/Kconfig" -+ - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 0abfe51704a0..c86c9e80d225 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -172,3 +172,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - - obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ -+ -+obj-$(CONFIG_HID_IPTS) += ipts/ -diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig -new file mode 100644 -index 000000000000..297401bd388d ---- /dev/null -+++ b/drivers/hid/ipts/Kconfig -@@ -0,0 +1,14 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+ -+config HID_IPTS -+ tristate "Intel Precise Touch & Stylus" -+ depends on INTEL_MEI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Precise Touch & Stylus (IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ipts. -diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile -new file mode 100644 -index 000000000000..883896f68e6a ---- /dev/null -+++ b/drivers/hid/ipts/Makefile -@@ -0,0 +1,16 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+# -+# Makefile for the IPTS touchscreen driver -+# -+ -+obj-$(CONFIG_HID_IPTS) += ipts.o -+ipts-objs := cmd.o -+ipts-objs += control.o -+ipts-objs += eds1.o -+ipts-objs += eds2.o -+ipts-objs += hid.o -+ipts-objs += main.o -+ipts-objs += mei.o -+ipts-objs += receiver.o -+ipts-objs += resources.o -+ipts-objs += thread.o -diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c -new file mode 100644 -index 000000000000..63a4934bbc5f ---- /dev/null -+++ b/drivers/hid/ipts/cmd.c -@@ -0,0 +1,61 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "mei.h" -+#include "spec-device.h" -+ -+int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp, u64 timeout) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!rsp) -+ return -EFAULT; -+ -+ /* -+ * In a response, the command code will have the most significant bit flipped to 1. -+ * If code is passed to ipts_mei_recv as is, no messages will be received. -+ */ -+ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); -+ if (ret < 0) -+ return ret; -+ -+ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); -+ -+ /* -+ * Some devices will always return this error. -+ * It is allowed to ignore it and to try continuing. -+ */ -+ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) -+ rsp->status = IPTS_STATUS_SUCCESS; -+ -+ return 0; -+} -+ -+int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) -+{ -+ struct ipts_command cmd = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.cmd = code; -+ -+ if (data && size > 0) -+ memcpy(cmd.payload, data, size); -+ -+ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); -+ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); -+} -diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h -new file mode 100644 -index 000000000000..2b4079075b64 ---- /dev/null -+++ b/drivers/hid/ipts/cmd.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CMD_H -+#define IPTS_CMD_H -+ -+#include -+ -+#include "context.h" -+#include "spec-device.h" -+ -+/* -+ * The default timeout for receiving responses -+ */ -+#define IPTS_CMD_DEFAULT_TIMEOUT 1000 -+ -+/** -+ * ipts_cmd_recv_timeout() - Receives a response to a command. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command / response. -+ * @rsp: The address that the received response will be copied to. -+ * @timeout: How many milliseconds the function will wait at most. -+ * -+ * A negative timeout means to wait forever. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp, u64 timeout); -+ -+/** -+ * ipts_cmd_recv() - Receives a response to a command. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command / response. -+ * @rsp: The address that the received response will be copied to. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, -+ struct ipts_response *rsp) -+{ -+ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); -+} -+ -+/** -+ * ipts_cmd_send() - Executes a command on the device. -+ * @ipts: The IPTS driver context. -+ * @code: The type of the command to execute. -+ * @data: The payload containing parameters for the command. -+ * @size: The size of the payload. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); -+ -+#endif /* IPTS_CMD_H */ -diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h -new file mode 100644 -index 000000000000..ba33259f1f7c ---- /dev/null -+++ b/drivers/hid/ipts/context.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CONTEXT_H -+#define IPTS_CONTEXT_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mei.h" -+#include "resources.h" -+#include "spec-device.h" -+#include "thread.h" -+ -+struct ipts_context { -+ struct device *dev; -+ struct ipts_mei mei; -+ -+ enum ipts_mode mode; -+ -+ /* -+ * Prevents concurrent GET_FEATURE reports. -+ */ -+ struct mutex feature_lock; -+ struct completion feature_event; -+ -+ /* -+ * These are not inside of struct ipts_resources -+ * because they don't own the memory they point to. -+ */ -+ struct ipts_buffer feature_report; -+ struct ipts_buffer descriptor; -+ -+ bool hid_active; -+ struct hid_device *hid; -+ -+ struct ipts_device_info info; -+ struct ipts_resources resources; -+ -+ struct ipts_thread receiver_loop; -+}; -+ -+#endif /* IPTS_CONTEXT_H */ -diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c -new file mode 100644 -index 000000000000..5360842d260b ---- /dev/null -+++ b/drivers/hid/ipts/control.c -@@ -0,0 +1,486 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "hid.h" -+#include "receiver.h" -+#include "resources.h" -+#include "spec-data.h" -+#include "spec-device.h" -+ -+static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!info) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ memcpy(info, rsp.payload, sizeof(*info)); -+ return 0; -+} -+ -+static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ struct ipts_set_mode cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.mode = mode; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) -+{ -+ int i = 0; -+ int ret = 0; -+ struct ipts_mem_window cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); -+ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); -+ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); -+ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); -+ } -+ -+ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); -+ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); -+ -+ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); -+ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); -+ -+ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); -+ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); -+ -+ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; -+ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+static int ipts_control_get_descriptor(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_data_header *header = NULL; -+ struct ipts_get_descriptor cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->resources.descriptor.address) -+ return -EFAULT; -+ -+ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); -+ -+ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); -+ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); -+ cmd.magic = 8; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ header = (struct ipts_data_header *)ipts->resources.descriptor.address; -+ -+ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { -+ ipts->descriptor.address = &header->data[8]; -+ ipts->descriptor.size = header->size - 8; -+ -+ return 0; -+ } -+ -+ return -ENODATA; -+} -+ -+int ipts_control_request_flush(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_quiesce_io cmd = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); -+ if (ret) -+ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_control_wait_flush(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (rsp.status == IPTS_STATUS_TIMEOUT) -+ return -EAGAIN; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_request_data(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); -+ if (ret) -+ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) -+{ -+ int ret = 0; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!shutdown) -+ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); -+ else -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); -+ -+ if (ret) { -+ if (ret != -EAGAIN) -+ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); -+ -+ return ret; -+ } -+ -+ /* -+ * During shutdown, it is possible that the sensor has already been disabled. -+ */ -+ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) -+ return 0; -+ -+ if (rsp.status == IPTS_STATUS_TIMEOUT) -+ return -EAGAIN; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) -+{ -+ int ret = 0; -+ struct ipts_feedback cmd = { 0 }; -+ struct ipts_response rsp = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ cmd.buffer = buffer; -+ -+ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); -+ if (ret) { -+ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); -+ if (ret) { -+ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * We don't know what feedback data looks like so we are sending zeros. -+ * See also ipts_control_refill_buffer. -+ */ -+ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) -+ return 0; -+ -+ if (rsp.status != IPTS_STATUS_SUCCESS) { -+ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); -+ return -EBADR; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, -+ enum ipts_feedback_data_type type, void *data, size_t size) -+{ -+ struct ipts_feedback_header *header = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->resources.hid2me.address) -+ return -EFAULT; -+ -+ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); -+ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; -+ -+ header->cmd_type = cmd; -+ header->data_type = type; -+ header->size = size; -+ header->buffer = IPTS_HID2ME_BUFFER; -+ -+ if (size + sizeof(*header) > ipts->resources.hid2me.size) -+ return -EINVAL; -+ -+ if (data && size > 0) -+ memcpy(header->payload, data, size); -+ -+ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); -+} -+ -+int ipts_control_start(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ struct ipts_device_info info = { 0 }; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "Starting IPTS\n"); -+ -+ ret = ipts_control_get_device_info(ipts, &info); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); -+ return ret; -+ } -+ -+ ipts->info = info; -+ -+ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); -+ return ret; -+ } -+ -+ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); -+ -+ /* -+ * Handle newer devices -+ */ -+ if (info.intf_eds > 1) { -+ /* -+ * Fetching the descriptor will only work on newer devices. -+ * For older devices, a fallback descriptor will be used. -+ */ -+ ret = ipts_control_get_descriptor(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * Newer devices can be directly initialized in polling mode. -+ */ -+ ipts->mode = IPTS_MODE_POLL; -+ } -+ -+ ret = ipts_control_set_mode(ipts, ipts->mode); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_set_mem_window(ipts, &ipts->resources); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_receiver_start(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_request_data(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request data: %d\n", ret); -+ return ret; -+ } -+ -+ ipts_hid_enable(ipts); -+ -+ ret = ipts_hid_init(ipts, info); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int _ipts_control_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ipts_hid_disable(ipts); -+ dev_info(ipts->dev, "Stopping IPTS\n"); -+ -+ ret = ipts_receiver_stop(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_resources_free(&ipts->resources); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ ret = _ipts_control_stop(ipts); -+ if (ret) -+ return ret; -+ -+ ret = ipts_hid_free(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_control_restart(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ ret = _ipts_control_stop(ipts); -+ if (ret) -+ return ret; -+ -+ /* -+ * Wait a second to give the sensor time to fully shut down. -+ */ -+ msleep(1000); -+ -+ ret = ipts_control_start(ipts); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h -new file mode 100644 -index 000000000000..26629c5144ed ---- /dev/null -+++ b/drivers/hid/ipts/control.h -@@ -0,0 +1,126 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_CONTROL_H -+#define IPTS_CONTROL_H -+ -+#include -+ -+#include "context.h" -+#include "spec-data.h" -+#include "spec-device.h" -+ -+/** -+ * ipts_control_request_flush() - Stop the data flow. -+ * @ipts: The IPTS driver context. -+ * -+ * Runs the command to stop the data flow on the device. -+ * All outstanding data needs to be acknowledged using feedback before the command will return. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_request_flush(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_flush() - Wait until data flow has been stopped. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_wait_flush(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_request_data(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_wait_data() - Wait until new data is available. -+ * @ipts: The IPTS driver context. -+ * @block: Whether to block execution until data is available. -+ * -+ * In poll mode, this function will never return while the data flow is active. Instead, -+ * the poll will be incremented when new data is available. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. -+ */ -+int ipts_control_wait_data(struct ipts_context *ipts, bool block); -+ -+/** -+ * ipts_control_send_feedback() - Submits a feedback buffer to the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The ID of the buffer containing feedback data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); -+ -+/** -+ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. -+ * @ipts: The IPTS driver context. -+ * @cmd: The command that will be run on the device. -+ * @type: The type of the payload that is sent to the device. -+ * @data: The payload of the feedback command. -+ * @size: The size of the payload. -+ * -+ * HID2ME feedback is a special type of feedback, because it allows interfacing with -+ * the HID API of the device at any moment, without requiring a buffer that has to -+ * be acknowledged. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, -+ enum ipts_feedback_data_type type, void *data, size_t size); -+ -+/** -+ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer that has been processed and can be refilled. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) -+{ -+ /* -+ * IPTS expects structured data in the feedback buffer matching the buffer that will be -+ * refilled. We don't know what that data looks like, so we just keep the buffer empty. -+ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. -+ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling -+ * the buffers on some devices. -+ */ -+ -+ return ipts_control_send_feedback(ipts, buffer); -+} -+ -+/** -+ * ipts_control_start() - Initialized the device and starts the data flow. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_start(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_stop() - Stops the data flow and resets the device. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_stop(struct ipts_context *ipts); -+ -+/** -+ * ipts_control_restart() - Stops the device and starts it again. -+ * @ipts: The IPTS driver context. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_control_restart(struct ipts_context *ipts); -+ -+#endif /* IPTS_CONTROL_H */ -diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h -new file mode 100644 -index 000000000000..307438c7c80c ---- /dev/null -+++ b/drivers/hid/ipts/desc.h -@@ -0,0 +1,80 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_DESC_H -+#define IPTS_DESC_H -+ -+#include -+ -+#define IPTS_HID_REPORT_SINGLETOUCH 64 -+#define IPTS_HID_REPORT_DATA 65 -+#define IPTS_HID_REPORT_SET_MODE 66 -+ -+#define IPTS_HID_REPORT_DATA_SIZE 7485 -+ -+/* -+ * HID descriptor for singletouch data. -+ * This descriptor should be present on all IPTS devices. -+ */ -+static const u8 ipts_singletouch_descriptor[] = { -+ 0x05, 0x0D, /* Usage Page (Digitizer), */ -+ 0x09, 0x04, /* Usage (Touchscreen), */ -+ 0xA1, 0x01, /* Collection (Application), */ -+ 0x85, 0x40, /* Report ID (64), */ -+ 0x09, 0x42, /* Usage (Tip Switch), */ -+ 0x15, 0x00, /* Logical Minimum (0), */ -+ 0x25, 0x01, /* Logical Maximum (1), */ -+ 0x75, 0x01, /* Report Size (1), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x95, 0x07, /* Report Count (7), */ -+ 0x81, 0x03, /* Input (Constant, Variable), */ -+ 0x05, 0x01, /* Usage Page (Desktop), */ -+ 0x09, 0x30, /* Usage (X), */ -+ 0x75, 0x10, /* Report Size (16), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0xA4, /* Push, */ -+ 0x55, 0x0E, /* Unit Exponent (14), */ -+ 0x65, 0x11, /* Unit (Centimeter), */ -+ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ -+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x09, 0x31, /* Usage (Y), */ -+ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ -+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0xB4, /* Pop, */ -+ 0xC0, /* End Collection */ -+}; -+ -+/* -+ * Fallback HID descriptor for older devices that do not have -+ * the ability to query their HID descriptor. -+ */ -+static const u8 ipts_fallback_descriptor[] = { -+ 0x05, 0x0D, /* Usage Page (Digitizer), */ -+ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ -+ 0xA1, 0x01, /* Collection (Application), */ -+ 0x85, 0x41, /* Report ID (65), */ -+ 0x09, 0x56, /* Usage (Scan Time), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0x75, 0x10, /* Report Size (16), */ -+ 0x81, 0x02, /* Input (Variable), */ -+ 0x09, 0x61, /* Usage (Gesture Char Quality), */ -+ 0x75, 0x08, /* Report Size (8), */ -+ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ -+ 0x81, 0x03, /* Input (Constant, Variable), */ -+ 0x85, 0x42, /* Report ID (66), */ -+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ -+ 0x09, 0xC8, /* Usage (C8h), */ -+ 0x75, 0x08, /* Report Size (8), */ -+ 0x95, 0x01, /* Report Count (1), */ -+ 0xB1, 0x02, /* Feature (Variable), */ -+ 0xC0, /* End Collection, */ -+}; -+ -+#endif /* IPTS_DESC_H */ -diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c -new file mode 100644 -index 000000000000..7b9f54388a9f ---- /dev/null -+++ b/drivers/hid/ipts/eds1.c -@@ -0,0 +1,104 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "eds1.h" -+#include "spec-device.h" -+ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, -+ sizeof(ipts_fallback_descriptor)); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == mode) -+ return 0; -+ -+ ipts->mode = mode; -+ -+ ret = ipts_control_restart(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_id != IPTS_HID_REPORT_SET_MODE) -+ return -EIO; -+ -+ if (report_type != HID_FEATURE_REPORT) -+ return -EIO; -+ -+ if (size != 2) -+ return -EINVAL; -+ -+ /* -+ * Implement mode switching report for older devices without native HID support. -+ */ -+ -+ if (request_type == HID_REQ_GET_REPORT) { -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ buffer[1] = ipts->mode; -+ } else if (request_type == HID_REQ_SET_REPORT) { -+ return ipts_eds1_switch_mode(ipts, buffer[1]); -+ } else { -+ return -EIO; -+ } -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h -new file mode 100644 -index 000000000000..eeeb6575e3e8 ---- /dev/null -+++ b/drivers/hid/ipts/eds1.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "context.h" -+ -+/** -+ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds1_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type); -diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c -new file mode 100644 -index 000000000000..639940794615 ---- /dev/null -+++ b/drivers/hid/ipts/eds2.c -@@ -0,0 +1,145 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "eds2.h" -+#include "spec-data.h" -+ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, -+ ipts->descriptor.size); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ mutex_lock(&ipts->feature_lock); -+ -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ -+ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); -+ reinit_completion(&ipts->feature_event); -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ goto out; -+ } -+ -+ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); -+ if (ret == 0) { -+ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ if (!ipts->feature_report.address) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (ipts->feature_report.size > size) { -+ ret = -ETOOSMALL; -+ goto out; -+ } -+ -+ ret = ipts->feature_report.size; -+ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); -+ -+out: -+ mutex_unlock(&ipts->feature_lock); -+ return ret; -+} -+ -+static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ buffer[0] = report_id; -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; -+ else -+ return -EIO; -+ -+ if (request_type == HID_REQ_GET_REPORT) -+ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); -+ else -+ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); -+} -diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h -new file mode 100644 -index 000000000000..064e3716907a ---- /dev/null -+++ b/drivers/hid/ipts/eds2.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+ -+#include "context.h" -+ -+/** -+ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds2_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type); -diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c -new file mode 100644 -index 000000000000..e34a1a4f9fa7 ---- /dev/null -+++ b/drivers/hid/ipts/hid.c -@@ -0,0 +1,225 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "desc.h" -+#include "eds1.h" -+#include "eds2.h" -+#include "hid.h" -+#include "spec-data.h" -+#include "spec-hid.h" -+ -+void ipts_hid_enable(struct ipts_context *ipts) -+{ -+ WRITE_ONCE(ipts->hid_active, true); -+} -+ -+void ipts_hid_disable(struct ipts_context *ipts) -+{ -+ WRITE_ONCE(ipts->hid_active, false); -+} -+ -+static int ipts_hid_start(struct hid_device *hid) -+{ -+ return 0; -+} -+ -+static void ipts_hid_stop(struct hid_device *hid) -+{ -+} -+ -+static int ipts_hid_parse(struct hid_device *hid) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ u8 *buffer = NULL; -+ size_t size = 0; -+ -+ if (!hid) -+ return -ENODEV; -+ -+ ipts = hid->driver_data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ if (ipts->info.intf_eds == 1) -+ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); -+ else -+ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ ret = hid_parse_report(hid, buffer, size); -+ kfree(buffer); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, -+ size_t size, unsigned char report_type, int request_type) -+{ -+ struct ipts_context *ipts = NULL; -+ -+ if (!hid) -+ return -ENODEV; -+ -+ ipts = hid->driver_data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ if (ipts->info.intf_eds == 1) { -+ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } else { -+ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } -+} -+ -+static struct hid_ll_driver ipts_hid_driver = { -+ .start = ipts_hid_start, -+ .stop = ipts_hid_stop, -+ .open = ipts_hid_start, -+ .close = ipts_hid_stop, -+ .parse = ipts_hid_parse, -+ .raw_request = ipts_hid_raw_request, -+}; -+ -+int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) -+{ -+ u8 *temp = NULL; -+ struct ipts_hid_header *frame = NULL; -+ struct ipts_data_header *header = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->hid) -+ return -ENODEV; -+ -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ -+ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; -+ -+ temp = ipts->resources.report.address; -+ memset(temp, 0, ipts->resources.report.size); -+ -+ if (!header) -+ return -EFAULT; -+ -+ if (header->size == 0) -+ return 0; -+ -+ if (header->type == IPTS_DATA_TYPE_HID) -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); -+ -+ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { -+ ipts->feature_report.address = header->data; -+ ipts->feature_report.size = header->size; -+ -+ complete_all(&ipts->feature_event); -+ return 0; -+ } -+ -+ if (header->type != IPTS_DATA_TYPE_FRAME) -+ return 0; -+ -+ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) -+ return -ERANGE; -+ -+ /* -+ * Synthesize a HID report matching the devices that natively send HID reports -+ */ -+ temp[0] = IPTS_HID_REPORT_DATA; -+ -+ frame = (struct ipts_hid_header *)&temp[3]; -+ frame->type = IPTS_HID_FRAME_TYPE_RAW; -+ frame->size = header->size + sizeof(*frame); -+ -+ memcpy(frame->data, header->data, header->size); -+ -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); -+} -+ -+int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->hid) -+ return 0; -+ -+ ipts->hid = hid_allocate_device(); -+ if (IS_ERR(ipts->hid)) { -+ int err = PTR_ERR(ipts->hid); -+ -+ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); -+ return err; -+ } -+ -+ ipts->hid->driver_data = ipts; -+ ipts->hid->dev.parent = ipts->dev; -+ ipts->hid->ll_driver = &ipts_hid_driver; -+ -+ ipts->hid->vendor = info.vendor; -+ ipts->hid->product = info.product; -+ ipts->hid->group = HID_GROUP_GENERIC; -+ -+ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, -+ info.product); -+ -+ ret = hid_add_device(ipts->hid); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); -+ ipts_hid_free(ipts); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_hid_free(struct ipts_context *ipts) -+{ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!ipts->hid) -+ return 0; -+ -+ hid_destroy_device(ipts->hid); -+ ipts->hid = NULL; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h -new file mode 100644 -index 000000000000..1ebe77447903 ---- /dev/null -+++ b/drivers/hid/ipts/hid.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2022-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_HID_H -+#define IPTS_HID_H -+ -+#include -+ -+#include "context.h" -+#include "spec-device.h" -+ -+void ipts_hid_enable(struct ipts_context *ipts); -+void ipts_hid_disable(struct ipts_context *ipts); -+ -+int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); -+ -+int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); -+int ipts_hid_free(struct ipts_context *ipts); -+ -+#endif /* IPTS_HID_H */ -diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c -new file mode 100644 -index 000000000000..fb5b5c13ee3e ---- /dev/null -+++ b/drivers/hid/ipts/main.c -@@ -0,0 +1,126 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "control.h" -+#include "mei.h" -+#include "receiver.h" -+#include "spec-device.h" -+ -+/* -+ * The MEI client ID for IPTS functionality. -+ */ -+#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) -+ -+static int ipts_set_dma_mask(struct mei_cl_device *cldev) -+{ -+ if (!cldev) -+ return -EFAULT; -+ -+ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) -+ return 0; -+ -+ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); -+} -+ -+static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) -+ return -EFAULT; -+ -+ ret = ipts_set_dma_mask(cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mei_cldev_enable(cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); -+ return ret; -+ } -+ -+ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); -+ if (!ipts) { -+ mei_cldev_disable(cldev); -+ return -ENOMEM; -+ } -+ -+ ret = ipts_mei_init(&ipts->mei, cldev); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); -+ return ret; -+ } -+ -+ ipts->dev = &cldev->dev; -+ ipts->mode = IPTS_MODE_EVENT; -+ -+ mutex_init(&ipts->feature_lock); -+ init_completion(&ipts->feature_event); -+ -+ mei_cldev_set_drvdata(cldev, ipts); -+ -+ ret = ipts_control_start(ipts); -+ if (ret) { -+ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void ipts_remove(struct mei_cl_device *cldev) -+{ -+ int ret = 0; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) { -+ pr_err("MEI device is NULL!"); -+ return; -+ } -+ -+ ipts = mei_cldev_get_drvdata(cldev); -+ -+ ret = ipts_control_stop(ipts); -+ if (ret) -+ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); -+ -+ mei_cldev_disable(cldev); -+} -+ -+static struct mei_cl_device_id ipts_device_id_table[] = { -+ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(mei, ipts_device_id_table); -+ -+static struct mei_cl_driver ipts_driver = { -+ .id_table = ipts_device_id_table, -+ .name = "ipts", -+ .probe = ipts_probe, -+ .remove = ipts_remove, -+}; -+module_mei_cl_driver(ipts_driver); -+ -+MODULE_DESCRIPTION("IPTS touchscreen driver"); -+MODULE_AUTHOR("Dorian Stoll "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c -new file mode 100644 -index 000000000000..1e0395ceae4a ---- /dev/null -+++ b/drivers/hid/ipts/mei.c -@@ -0,0 +1,188 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "context.h" -+#include "mei.h" -+ -+static void locked_list_add(struct list_head *new, struct list_head *head, -+ struct rw_semaphore *lock) -+{ -+ down_write(lock); -+ list_add(new, head); -+ up_write(lock); -+} -+ -+static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) -+{ -+ down_write(lock); -+ list_del(entry); -+ up_write(lock); -+} -+ -+static void ipts_mei_incoming(struct mei_cl_device *cldev) -+{ -+ ssize_t ret = 0; -+ struct ipts_mei_message *entry = NULL; -+ struct ipts_context *ipts = NULL; -+ -+ if (!cldev) { -+ pr_err("MEI device is NULL!"); -+ return; -+ } -+ -+ ipts = mei_cldev_get_drvdata(cldev); -+ if (!ipts) { -+ pr_err("IPTS driver context is NULL!"); -+ return; -+ } -+ -+ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); -+ if (!entry) -+ return; -+ -+ INIT_LIST_HEAD(&entry->list); -+ -+ do { -+ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); -+ } while (ret == -EINTR); -+ -+ if (ret < 0) { -+ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); -+ return; -+ } -+ -+ if (ret == 0) { -+ dev_err(ipts->dev, "Received empty response\n"); -+ return; -+ } -+ -+ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); -+ wake_up_all(&ipts->mei.message_queue); -+} -+ -+static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, -+ struct ipts_response *rsp) -+{ -+ struct ipts_mei_message *entry = NULL; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!rsp) -+ return -EFAULT; -+ -+ down_read(&mei->message_lock); -+ -+ /* -+ * Iterate over the list of received messages, and check if there is one -+ * matching the requested command code. -+ */ -+ list_for_each_entry(entry, &mei->messages, list) { -+ if (entry->rsp.cmd == code) -+ break; -+ } -+ -+ up_read(&mei->message_lock); -+ -+ /* -+ * If entry is not the list head, this means that the loop above has been stopped early, -+ * and that we found a matching element. We drop the message from the list and return it. -+ */ -+ if (!list_entry_is_head(entry, &mei->messages, list)) { -+ locked_list_del(&entry->list, &mei->message_lock); -+ -+ *rsp = entry->rsp; -+ devm_kfree(&mei->cldev->dev, entry); -+ -+ return 0; -+ } -+ -+ return -EAGAIN; -+} -+ -+int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, -+ u64 timeout) -+{ -+ int ret = 0; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ /* -+ * A timeout of 0 means check and return immideately. -+ */ -+ if (timeout == 0) -+ return ipts_mei_search(mei, code, rsp); -+ -+ /* -+ * A timeout of less than 0 means to wait forever. -+ */ -+ if (timeout < 0) { -+ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); -+ return 0; -+ } -+ -+ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, -+ msecs_to_jiffies(timeout)); -+ -+ if (ret > 0) -+ return 0; -+ -+ return -EAGAIN; -+} -+ -+int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) -+{ -+ int ret = 0; -+ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!mei->cldev) -+ return -EFAULT; -+ -+ if (!data) -+ return -EFAULT; -+ -+ do { -+ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); -+ } while (ret == -EINTR); -+ -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) -+{ -+ if (!mei) -+ return -EFAULT; -+ -+ if (!cldev) -+ return -EFAULT; -+ -+ mei->cldev = cldev; -+ -+ INIT_LIST_HEAD(&mei->messages); -+ init_waitqueue_head(&mei->message_queue); -+ init_rwsem(&mei->message_lock); -+ -+ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h -new file mode 100644 -index 000000000000..973bade6b0fd ---- /dev/null -+++ b/drivers/hid/ipts/mei.h -@@ -0,0 +1,66 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_MEI_H -+#define IPTS_MEI_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "spec-device.h" -+ -+struct ipts_mei_message { -+ struct list_head list; -+ struct ipts_response rsp; -+}; -+ -+struct ipts_mei { -+ struct mei_cl_device *cldev; -+ -+ struct list_head messages; -+ -+ wait_queue_head_t message_queue; -+ struct rw_semaphore message_lock; -+}; -+ -+/** -+ * ipts_mei_recv() - Receive data from a MEI device. -+ * @mei: The IPTS MEI device context. -+ * @code: The IPTS command code to look for. -+ * @rsp: The address that the received data will be copied to. -+ * @timeout: How many milliseconds the function will wait at most. -+ * -+ * A negative timeout means to wait forever. -+ * -+ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. -+ */ -+int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, -+ u64 timeout); -+ -+/** -+ * ipts_mei_send() - Send data to a MEI device. -+ * @ipts: The IPTS MEI device context. -+ * @data: The data to send. -+ * @size: The size of the data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); -+ -+/** -+ * ipts_mei_init() - Initialize the MEI device context. -+ * @mei: The MEI device context to initialize. -+ * @cldev: The MEI device the context will be bound to. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); -+ -+#endif /* IPTS_MEI_H */ -diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -new file mode 100644 -index 000000000000..977724c728c3 ---- /dev/null -+++ b/drivers/hid/ipts/receiver.c -@@ -0,0 +1,251 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cmd.h" -+#include "context.h" -+#include "control.h" -+#include "hid.h" -+#include "receiver.h" -+#include "resources.h" -+#include "spec-device.h" -+#include "thread.h" -+ -+static void ipts_receiver_next_doorbell(struct ipts_context *ipts) -+{ -+ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; -+ *doorbell = *doorbell + 1; -+} -+ -+static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) -+{ -+ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; -+ return *doorbell; -+} -+ -+static void ipts_receiver_backoff(time64_t last, u32 n) -+{ -+ /* -+ * If the last change was less than n seconds ago, -+ * sleep for a shorter period so that new data can be -+ * processed quickly. If there was no change for more than -+ * n seconds, sleep longer to avoid wasting CPU cycles. -+ */ -+ if (last + n > ktime_get_seconds()) -+ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); -+ else -+ msleep(200); -+} -+ -+static int ipts_receiver_event_loop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ u32 buffer = 0; -+ -+ struct ipts_context *ipts = NULL; -+ time64_t last = ktime_get_seconds(); -+ -+ if (!thread) -+ return -EFAULT; -+ -+ ipts = thread->data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "IPTS running in event mode\n"); -+ -+ while (!ipts_thread_should_stop(thread)) { -+ int i = 0; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_control_wait_data(ipts, false); -+ if (ret == -EAGAIN) -+ break; -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ continue; -+ } -+ -+ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; -+ ipts_receiver_next_doorbell(ipts); -+ -+ ret = ipts_hid_input_data(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); -+ -+ ret = ipts_control_refill_buffer(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); -+ -+ ret = ipts_control_request_data(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to request data: %d\n", ret); -+ -+ last = ktime_get_seconds(); -+ } -+ -+ ipts_receiver_backoff(last, 5); -+ } -+ -+ ret = ipts_control_request_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); -+ return ret; -+ } -+ -+ ret = ipts_control_wait_data(ipts, true); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ ret = ipts_control_wait_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ return 0; -+} -+ -+static int ipts_receiver_poll_loop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ u32 buffer = 0; -+ -+ u32 doorbell = 0; -+ u32 lastdb = 0; -+ -+ struct ipts_context *ipts = NULL; -+ time64_t last = ktime_get_seconds(); -+ -+ if (!thread) -+ return -EFAULT; -+ -+ ipts = thread->data; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ dev_info(ipts->dev, "IPTS running in poll mode\n"); -+ -+ while (true) { -+ if (ipts_thread_should_stop(thread)) { -+ ret = ipts_control_request_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ doorbell = ipts_receiver_current_doorbell(ipts); -+ -+ /* -+ * After filling up one of the data buffers, IPTS will increment -+ * the doorbell. The value of the doorbell stands for the *next* -+ * buffer that IPTS is going to fill. -+ */ -+ while (lastdb != doorbell) { -+ buffer = lastdb % IPTS_BUFFERS; -+ -+ ret = ipts_hid_input_data(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); -+ -+ ret = ipts_control_refill_buffer(ipts, buffer); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); -+ -+ last = ktime_get_seconds(); -+ lastdb++; -+ } -+ -+ if (ipts_thread_should_stop(thread)) -+ break; -+ -+ ipts_receiver_backoff(last, 5); -+ } -+ -+ ret = ipts_control_wait_data(ipts, true); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ ret = ipts_control_wait_flush(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); -+ -+ if (ret != -EAGAIN) -+ return ret; -+ else -+ return 0; -+ } -+ -+ return 0; -+} -+ -+int ipts_receiver_start(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == IPTS_MODE_EVENT) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, -+ "ipts_event"); -+ } else if (ipts->mode == IPTS_MODE_POLL) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, -+ "ipts_poll"); -+ } else { -+ ret = -EINVAL; -+ } -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int ipts_receiver_stop(struct ipts_context *ipts) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ ret = ipts_thread_stop(&ipts->receiver_loop); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h -new file mode 100644 -index 000000000000..3de7da62d40c ---- /dev/null -+++ b/drivers/hid/ipts/receiver.h -@@ -0,0 +1,16 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_RECEIVER_H -+#define IPTS_RECEIVER_H -+ -+#include "context.h" -+ -+int ipts_receiver_start(struct ipts_context *ipts); -+int ipts_receiver_stop(struct ipts_context *ipts); -+ -+#endif /* IPTS_RECEIVER_H */ -diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c -new file mode 100644 -index 000000000000..cc14653b2a9f ---- /dev/null -+++ b/drivers/hid/ipts/resources.c -@@ -0,0 +1,131 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+ -+#include "desc.h" -+#include "resources.h" -+#include "spec-device.h" -+ -+static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) -+{ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (buffer->address) -+ return 0; -+ -+ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); -+ -+ if (!buffer->address) -+ return -ENOMEM; -+ -+ buffer->size = size; -+ buffer->device = dev; -+ -+ return 0; -+} -+ -+static void ipts_resources_free_buffer(struct ipts_buffer *buffer) -+{ -+ if (!buffer->address) -+ return; -+ -+ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); -+ -+ buffer->address = NULL; -+ buffer->size = 0; -+ -+ buffer->dma_address = 0; -+ buffer->device = NULL; -+} -+ -+int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) -+{ -+ int ret = 0; -+ -+ /* -+ * Some compilers (AOSP clang) complain about a redefined -+ * variable when this is declared inside of the for loop. -+ */ -+ int i = 0; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); -+ if (ret) -+ goto err; -+ } -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { -+ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); -+ if (ret) -+ goto err; -+ } -+ -+ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); -+ if (ret) -+ goto err; -+ -+ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); -+ if (ret) -+ goto err; -+ -+ if (!res->report.address) { -+ res->report.size = IPTS_HID_REPORT_DATA_SIZE; -+ res->report.address = kzalloc(res->report.size, GFP_KERNEL); -+ -+ if (!res->report.address) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } -+ -+ return 0; -+ -+err: -+ -+ ipts_resources_free(res); -+ return ret; -+} -+ -+int ipts_resources_free(struct ipts_resources *res) -+{ -+ int i = 0; -+ -+ if (!res) -+ return -EFAULT; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) -+ ipts_resources_free_buffer(&res->data[i]); -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) -+ ipts_resources_free_buffer(&res->feedback[i]); -+ -+ ipts_resources_free_buffer(&res->doorbell); -+ ipts_resources_free_buffer(&res->workqueue); -+ ipts_resources_free_buffer(&res->hid2me); -+ ipts_resources_free_buffer(&res->descriptor); -+ -+ kfree(res->report.address); -+ res->report.address = NULL; -+ res->report.size = 0; -+ -+ return 0; -+} -diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h -new file mode 100644 -index 000000000000..2068e13285f0 ---- /dev/null -+++ b/drivers/hid/ipts/resources.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_RESOURCES_H -+#define IPTS_RESOURCES_H -+ -+#include -+#include -+ -+#include "spec-device.h" -+ -+struct ipts_buffer { -+ u8 *address; -+ size_t size; -+ -+ dma_addr_t dma_address; -+ struct device *device; -+}; -+ -+struct ipts_resources { -+ struct ipts_buffer data[IPTS_BUFFERS]; -+ struct ipts_buffer feedback[IPTS_BUFFERS]; -+ -+ struct ipts_buffer doorbell; -+ struct ipts_buffer workqueue; -+ struct ipts_buffer hid2me; -+ -+ struct ipts_buffer descriptor; -+ -+ // Buffer for synthesizing HID reports -+ struct ipts_buffer report; -+}; -+ -+int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); -+int ipts_resources_free(struct ipts_resources *res); -+ -+#endif /* IPTS_RESOURCES_H */ -diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h -new file mode 100644 -index 000000000000..e8dd98895a7e ---- /dev/null -+++ b/drivers/hid/ipts/spec-data.h -@@ -0,0 +1,100 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_DATA_H -+#define IPTS_SPEC_DATA_H -+ -+#include -+#include -+ -+/** -+ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. -+ */ -+enum ipts_feedback_cmd_type { -+ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, -+ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, -+ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, -+ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, -+}; -+ -+/** -+ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. -+ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. -+ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. -+ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. -+ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. -+ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. -+ */ -+enum ipts_feedback_data_type { -+ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, -+ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, -+ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, -+ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, -+ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, -+}; -+ -+/** -+ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. -+ * @cmd_type: A command that should be executed on the sensor. -+ * @size: The size of the payload to be written. -+ * @buffer: The ID of the buffer that contains this feedback data. -+ * @protocol: The protocol version of the EDS. -+ * @data_type: The type of data that the buffer contains. -+ * @spi_offset: The offset at which to write the payload data to the sensor. -+ * @payload: Payload for the feedback command, or 0 if no payload is sent. -+ */ -+struct ipts_feedback_header { -+ enum ipts_feedback_cmd_type cmd_type; -+ u32 size; -+ u32 buffer; -+ u32 protocol; -+ enum ipts_feedback_data_type data_type; -+ u32 spi_offset; -+ u8 reserved[40]; -+ u8 payload[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_feedback_header) == 64); -+ -+/** -+ * enum ipts_data_type - Defines what type of data a buffer contains. -+ * @IPTS_DATA_TYPE_FRAME: Raw data frame. -+ * @IPTS_DATA_TYPE_ERROR: Error data. -+ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. -+ * @IPTS_DATA_TYPE_HID: A HID report. -+ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. -+ */ -+enum ipts_data_type { -+ IPTS_DATA_TYPE_FRAME = 0x00, -+ IPTS_DATA_TYPE_ERROR = 0x01, -+ IPTS_DATA_TYPE_VENDOR = 0x02, -+ IPTS_DATA_TYPE_HID = 0x03, -+ IPTS_DATA_TYPE_GET_FEATURES = 0x04, -+ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, -+}; -+ -+/** -+ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. -+ * @type: What data the buffer contains. -+ * @size: How much data the buffer contains. -+ * @buffer: Which buffer the data is in. -+ */ -+struct ipts_data_header { -+ enum ipts_data_type type; -+ u32 size; -+ u32 buffer; -+ u8 reserved[52]; -+ u8 data[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_data_header) == 64); -+ -+#endif /* IPTS_SPEC_DATA_H */ -diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h -new file mode 100644 -index 000000000000..41845f9d9025 ---- /dev/null -+++ b/drivers/hid/ipts/spec-device.h -@@ -0,0 +1,290 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_DEVICE_H -+#define IPTS_SPEC_DEVICE_H -+ -+#include -+#include -+ -+/* -+ * The amount of buffers that IPTS can use for data transfer. -+ */ -+#define IPTS_BUFFERS 16 -+ -+/* -+ * The buffer ID that is used for HID2ME feedback -+ */ -+#define IPTS_HID2ME_BUFFER IPTS_BUFFERS -+ -+/** -+ * enum ipts_command - Commands that can be sent to the IPTS hardware. -+ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. -+ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. -+ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. -+ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. -+ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. -+ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. -+ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. -+ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. -+ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. -+ */ -+enum ipts_command_code { -+ IPTS_CMD_GET_DEVICE_INFO = 0x01, -+ IPTS_CMD_SET_MODE = 0x02, -+ IPTS_CMD_SET_MEM_WINDOW = 0x03, -+ IPTS_CMD_QUIESCE_IO = 0x04, -+ IPTS_CMD_READY_FOR_DATA = 0x05, -+ IPTS_CMD_FEEDBACK = 0x06, -+ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, -+ IPTS_CMD_RESET_SENSOR = 0x0B, -+ IPTS_CMD_GET_DESCRIPTOR = 0x0F, -+}; -+ -+/** -+ * enum ipts_status - Possible status codes returned by the IPTS device. -+ * @IPTS_STATUS_SUCCESS: Operation completed successfully. -+ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. -+ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. -+ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. -+ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. -+ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. -+ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. -+ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. -+ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. -+ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. -+ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. -+ * The host can ignore this error and attempt to continue. -+ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. -+ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. -+ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. -+ * @IPTS_STATUS_TIMEOUT: The operation timed out. -+ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. -+ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. -+ * Further progress is not possible. -+ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. -+ * The driver can attempt to continue. -+ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. -+ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. -+ */ -+enum ipts_status { -+ IPTS_STATUS_SUCCESS = 0x00, -+ IPTS_STATUS_INVALID_PARAMS = 0x01, -+ IPTS_STATUS_ACCESS_DENIED = 0x02, -+ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, -+ IPTS_STATUS_NOT_READY = 0x04, -+ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, -+ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, -+ IPTS_STATUS_OUT_OF_MEMORY = 0x07, -+ IPTS_STATUS_INTERNAL_ERROR = 0x08, -+ IPTS_STATUS_SENSOR_DISABLED = 0x09, -+ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, -+ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, -+ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, -+ IPTS_STATUS_RESET_FAILED = 0x0D, -+ IPTS_STATUS_TIMEOUT = 0x0E, -+ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, -+ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, -+ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, -+ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, -+ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, -+}; -+ -+/** -+ * struct ipts_command - Message that is sent to the device for calling a command. -+ * @cmd: The command that will be called. -+ * @payload: Payload containing parameters for the called command. -+ */ -+struct ipts_command { -+ enum ipts_command_code cmd; -+ u8 payload[320]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_command) == 324); -+ -+/** -+ * enum ipts_mode - Configures what data the device produces and how its sent. -+ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. -+ * Older devices will return singletouch data in this mode. -+ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. -+ * Older devices will return multitouch data in this mode. -+ */ -+enum ipts_mode { -+ IPTS_MODE_EVENT = 0x00, -+ IPTS_MODE_POLL = 0x01, -+}; -+ -+/** -+ * struct ipts_set_mode - Payload for the SET_MODE command. -+ * @mode: Changes the mode that IPTS will operate in. -+ */ -+struct ipts_set_mode { -+ enum ipts_mode mode; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_set_mode) == 16); -+ -+#define IPTS_WORKQUEUE_SIZE 8192 -+#define IPTS_WORKQUEUE_ITEM_SIZE 16 -+ -+/** -+ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. -+ * @data_addr_lower: Lower 32 bits of the data buffer addresses. -+ * @data_addr_upper: Upper 32 bits of the data buffer addresses. -+ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. -+ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. -+ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. -+ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. -+ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. -+ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. -+ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. -+ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. -+ * @hid2me_size: Size of the hid2me feedback buffer. -+ * @workqueue_item_size: Magic value. Must be 16. -+ * @workqueue_size: Magic value. Must be 8192. -+ * -+ * The workqueue related items in this struct are required for using -+ * GuC submission with binary processing firmware. Since this driver does -+ * not use GuC submission and instead exports raw data to userspace, these -+ * items are not actually used, but they need to be allocated and passed -+ * to the device, otherwise initialization will fail. -+ */ -+struct ipts_mem_window { -+ u32 data_addr_lower[IPTS_BUFFERS]; -+ u32 data_addr_upper[IPTS_BUFFERS]; -+ u32 workqueue_addr_lower; -+ u32 workqueue_addr_upper; -+ u32 doorbell_addr_lower; -+ u32 doorbell_addr_upper; -+ u32 feedback_addr_lower[IPTS_BUFFERS]; -+ u32 feedback_addr_upper[IPTS_BUFFERS]; -+ u32 hid2me_addr_lower; -+ u32 hid2me_addr_upper; -+ u32 hid2me_size; -+ u8 reserved1; -+ u8 workqueue_item_size; -+ u16 workqueue_size; -+ u8 reserved[32]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_mem_window) == 320); -+ -+/** -+ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. -+ */ -+struct ipts_quiesce_io { -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_quiesce_io) == 12); -+ -+/** -+ * struct ipts_feedback - Payload for the FEEDBACK command. -+ * @buffer: The buffer that the device should refill. -+ */ -+struct ipts_feedback { -+ u32 buffer; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_feedback) == 16); -+ -+/** -+ * enum ipts_reset_type - Possible ways of resetting the device. -+ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. -+ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. -+ */ -+enum ipts_reset_type { -+ IPTS_RESET_TYPE_HARD = 0x00, -+ IPTS_RESET_TYPE_SOFT = 0x01, -+}; -+ -+/** -+ * struct ipts_reset - Payload for the RESET_SENSOR command. -+ * @type: How the device should get reset. -+ */ -+struct ipts_reset_sensor { -+ enum ipts_reset_type type; -+ u8 reserved[4]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_reset_sensor) == 8); -+ -+/** -+ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. -+ * @addr_lower: The lower 32 bits of the descriptor buffer address. -+ * @addr_upper: The upper 32 bits of the descriptor buffer address. -+ * @magic: A magic value. Must be 8. -+ */ -+struct ipts_get_descriptor { -+ u32 addr_lower; -+ u32 addr_upper; -+ u32 magic; -+ u8 reserved[12]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_get_descriptor) == 24); -+ -+/* -+ * The type of a response is indicated by a -+ * command code, with the most significant bit flipped to 1. -+ */ -+#define IPTS_RSP_BIT BIT(31) -+ -+/** -+ * struct ipts_response - Data returned from the device in response to a command. -+ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). -+ * @status: The return code of the command. -+ * @payload: The data that was produced by the command. -+ */ -+struct ipts_response { -+ enum ipts_command_code cmd; -+ enum ipts_status status; -+ u8 payload[80]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_response) == 88); -+ -+/** -+ * struct ipts_device_info - Vendor information of the IPTS device. -+ * @vendor: Vendor ID of this device. -+ * @product: Product ID of this device. -+ * @hw_version: Hardware revision of this device. -+ * @fw_version: Firmware revision of this device. -+ * @data_size: Requested size for a data buffer. -+ * @feedback_size: Requested size for a feedback buffer. -+ * @mode: Mode that the device currently operates in. -+ * @max_contacts: Maximum amount of concurrent touches the sensor can process. -+ * @sensor_min_eds: The minimum EDS version supported by the sensor. -+ * @sensor_max_eds: The maximum EDS version supported by the sensor. -+ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. -+ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. -+ * @intf_eds: The EDS version implemented by the interface between ME and host. -+ */ -+struct ipts_device_info { -+ u16 vendor; -+ u16 product; -+ u32 hw_version; -+ u32 fw_version; -+ u32 data_size; -+ u32 feedback_size; -+ enum ipts_mode mode; -+ u8 max_contacts; -+ u8 reserved1[3]; -+ u8 sensor_min_eds; -+ u8 sensor_maj_eds; -+ u8 me_min_eds; -+ u8 me_maj_eds; -+ u8 intf_eds; -+ u8 reserved2[11]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_device_info) == 44); -+ -+#endif /* IPTS_SPEC_DEVICE_H */ -diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h -new file mode 100644 -index 000000000000..5a58d4a0a610 ---- /dev/null -+++ b/drivers/hid/ipts/spec-hid.h -@@ -0,0 +1,34 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2020-2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_SPEC_HID_H -+#define IPTS_SPEC_HID_H -+ -+#include -+#include -+ -+/* -+ * Made-up type for passing raw IPTS data in a HID report. -+ */ -+#define IPTS_HID_FRAME_TYPE_RAW 0xEE -+ -+/** -+ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. -+ * @size: Size of the data inside the report, including this header. -+ * @type: What type of data does this report contain. -+ */ -+struct ipts_hid_header { -+ u32 size; -+ u8 reserved1; -+ u8 type; -+ u8 reserved2; -+ u8 data[]; -+} __packed; -+ -+static_assert(sizeof(struct ipts_hid_header) == 7); -+ -+#endif /* IPTS_SPEC_HID_H */ -diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c -new file mode 100644 -index 000000000000..355e92bea26f ---- /dev/null -+++ b/drivers/hid/ipts/thread.c -@@ -0,0 +1,84 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "thread.h" -+ -+bool ipts_thread_should_stop(struct ipts_thread *thread) -+{ -+ if (!thread) -+ return false; -+ -+ return READ_ONCE(thread->should_stop); -+} -+ -+static int ipts_thread_runner(void *data) -+{ -+ int ret = 0; -+ struct ipts_thread *thread = data; -+ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!thread->threadfn) -+ return -EFAULT; -+ -+ ret = thread->threadfn(thread); -+ complete_all(&thread->done); -+ -+ return ret; -+} -+ -+int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), -+ void *data, const char *name) -+{ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!threadfn) -+ return -EFAULT; -+ -+ init_completion(&thread->done); -+ -+ thread->data = data; -+ thread->should_stop = false; -+ thread->threadfn = threadfn; -+ -+ thread->thread = kthread_run(ipts_thread_runner, thread, name); -+ return PTR_ERR_OR_ZERO(thread->thread); -+} -+ -+int ipts_thread_stop(struct ipts_thread *thread) -+{ -+ int ret = 0; -+ -+ if (!thread) -+ return -EFAULT; -+ -+ if (!thread->thread) -+ return 0; -+ -+ WRITE_ONCE(thread->should_stop, true); -+ -+ /* -+ * Make sure that the write has gone through before waiting. -+ */ -+ wmb(); -+ -+ wait_for_completion(&thread->done); -+ ret = kthread_stop(thread->thread); -+ -+ thread->thread = NULL; -+ thread->data = NULL; -+ thread->threadfn = NULL; -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h -new file mode 100644 -index 000000000000..1f966b8b32c4 ---- /dev/null -+++ b/drivers/hid/ipts/thread.h -@@ -0,0 +1,59 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#ifndef IPTS_THREAD_H -+#define IPTS_THREAD_H -+ -+#include -+#include -+#include -+ -+/* -+ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible -+ * to issue MEI commands from that thread while it shuts itself down. By using a custom -+ * boolean variable and a completion object, we can call kthread_stop only when the thread -+ * already finished all of its work and has returned. -+ */ -+struct ipts_thread { -+ struct task_struct *thread; -+ -+ bool should_stop; -+ struct completion done; -+ -+ void *data; -+ int (*threadfn)(struct ipts_thread *thread); -+}; -+ -+/** -+ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. -+ * @thread: The current thread. -+ * -+ * Returns: true if the thread should stop, false if not. -+ */ -+bool ipts_thread_should_stop(struct ipts_thread *thread); -+ -+/** -+ * ipts_thread_start() - Starts an IPTS thread. -+ * @thread: The thread to initialize and start. -+ * @threadfn: The function to execute. -+ * @data: An argument that will be passed to threadfn. -+ * @name: The name of the new thread. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), -+ void *data, const char name[]); -+ -+/** -+ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. -+ * @thread: The thread that should stop. -+ * -+ * Returns: The return value of the thread function. -+ */ -+int ipts_thread_stop(struct ipts_thread *thread); -+ -+#endif /* IPTS_THREAD_H */ --- -2.49.0 - diff --git a/patches/6.13-fedora/0006-ithc.patch b/patches/6.13-fedora/0006-ithc.patch deleted file mode 100644 index a4ca4ecbac..0000000000 --- a/patches/6.13-fedora/0006-ithc.patch +++ /dev/null @@ -1,2771 +0,0 @@ -From 7dbcb0c475dacbbaec0ae72c3c74c8d3087109e6 Mon Sep 17 00:00:00 2001 -From: Dorian Stoll -Date: Sun, 11 Dec 2022 12:03:38 +0100 -Subject: [PATCH] iommu: intel: Disable source id verification for ITHC - -Signed-off-by: Dorian Stoll -Patchset: ithc ---- - drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 466c1412dd45..565686813588 100644 ---- a/drivers/iommu/intel/irq_remapping.c -+++ b/drivers/iommu/intel/irq_remapping.c -@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) - data.busmatch_count = 0; - pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); - -+ /* -+ * The Intel Touch Host Controller is at 00:10.6, but for some reason -+ * the MSI interrupts have request id 01:05.0. -+ * Disable id verification to work around this. -+ * FIXME Find proper fix or turn this into a quirk. -+ */ -+ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { -+ switch(dev->device) { -+ case 0x98d0: case 0x98d1: // LKF -+ case 0xa0d0: case 0xa0d1: // TGL LP -+ case 0x43d0: case 0x43d1: // TGL H -+ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); -+ return 0; -+ } -+ } -+ - /* - * DMA alias provides us with a PCI device and alias. The only case - * where the it will return an alias on a different bus than the --- -2.49.0 - -From 9af03ac81e7098a54bf697e915d5a4163fba65bd Mon Sep 17 00:00:00 2001 -From: quo -Date: Sun, 11 Dec 2022 12:10:54 +0100 -Subject: [PATCH] hid: Add support for Intel Touch Host Controller - -Based on quo/ithc-linux@34539af4726d. - -Signed-off-by: Maximilian Stoll -Patchset: ithc ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 1 + - drivers/hid/ithc/Kbuild | 6 + - drivers/hid/ithc/Kconfig | 12 + - drivers/hid/ithc/ithc-debug.c | 149 ++++++++ - drivers/hid/ithc/ithc-debug.h | 7 + - drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ - drivers/hid/ithc/ithc-dma.h | 47 +++ - drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ - drivers/hid/ithc/ithc-hid.h | 32 ++ - drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ - drivers/hid/ithc/ithc-legacy.h | 8 + - drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ - drivers/hid/ithc/ithc-quickspi.h | 39 ++ - drivers/hid/ithc/ithc-regs.c | 154 ++++++++ - drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ - drivers/hid/ithc/ithc.h | 89 +++++ - 18 files changed, 2568 insertions(+) - create mode 100644 drivers/hid/ithc/Kbuild - create mode 100644 drivers/hid/ithc/Kconfig - create mode 100644 drivers/hid/ithc/ithc-debug.c - create mode 100644 drivers/hid/ithc/ithc-debug.h - create mode 100644 drivers/hid/ithc/ithc-dma.c - create mode 100644 drivers/hid/ithc/ithc-dma.h - create mode 100644 drivers/hid/ithc/ithc-hid.c - create mode 100644 drivers/hid/ithc/ithc-hid.h - create mode 100644 drivers/hid/ithc/ithc-legacy.c - create mode 100644 drivers/hid/ithc/ithc-legacy.h - create mode 100644 drivers/hid/ithc/ithc-main.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.c - create mode 100644 drivers/hid/ithc/ithc-quickspi.h - create mode 100644 drivers/hid/ithc/ithc-regs.c - create mode 100644 drivers/hid/ithc/ithc-regs.h - create mode 100644 drivers/hid/ithc/ithc.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index d36a55e58598..ff709b2cb72b 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1391,4 +1391,6 @@ source "drivers/hid/intel-thc-hid/Kconfig" - - source "drivers/hid/ipts/Kconfig" - -+source "drivers/hid/ithc/Kconfig" -+ - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index c86c9e80d225..046eb5fd8017 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -174,3 +174,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ - - obj-$(CONFIG_HID_IPTS) += ipts/ -+obj-$(CONFIG_HID_ITHC) += ithc/ -diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild -new file mode 100644 -index 000000000000..4937ba131297 ---- /dev/null -+++ b/drivers/hid/ithc/Kbuild -@@ -0,0 +1,6 @@ -+obj-$(CONFIG_HID_ITHC) := ithc.o -+ -+ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o -+ -+ccflags-y := -std=gnu11 -Wno-declaration-after-statement -+ -diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig -new file mode 100644 -index 000000000000..ede713023609 ---- /dev/null -+++ b/drivers/hid/ithc/Kconfig -@@ -0,0 +1,12 @@ -+config HID_ITHC -+ tristate "Intel Touch Host Controller" -+ depends on PCI -+ depends on HID -+ help -+ Say Y here if your system has a touchscreen using Intels -+ Touch Host Controller (ITHC / IPTS) technology. -+ -+ If unsure say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ithc. -diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c -new file mode 100644 -index 000000000000..2d8c6afe9966 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.c -@@ -0,0 +1,149 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+void ithc_log_regs(struct ithc *ithc) -+{ -+ if (!ithc->prev_regs) -+ return; -+ u32 __iomem *cur = (__iomem void *)ithc->regs; -+ u32 *prev = (void *)ithc->prev_regs; -+ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { -+ u32 x = readl(cur + i); -+ if (x != prev[i]) { -+ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); -+ prev[i] = x; -+ } -+ } -+} -+ -+static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, -+ loff_t *offset) -+{ -+ // Debug commands consist of a single letter followed by a list of numbers (decimal or -+ // hexadecimal, space-separated). -+ struct ithc *ithc = file_inode(f)->i_private; -+ char cmd[256]; -+ if (!ithc || !ithc->pci) -+ return -ENODEV; -+ if (!len) -+ return -EINVAL; -+ if (len >= sizeof(cmd)) -+ return -EINVAL; -+ if (copy_from_user(cmd, buf, len)) -+ return -EFAULT; -+ cmd[len] = 0; -+ if (cmd[len-1] == '\n') -+ cmd[len-1] = 0; -+ pci_info(ithc->pci, "debug command: %s\n", cmd); -+ -+ // Parse the list of arguments into a u32 array. -+ u32 n = 0; -+ const char *s = cmd + 1; -+ u32 a[32]; -+ while (*s && *s != '\n') { -+ if (n >= ARRAY_SIZE(a)) -+ return -EINVAL; -+ if (*s++ != ' ') -+ return -EINVAL; -+ char *e; -+ a[n++] = simple_strtoul(s, &e, 0); -+ if (e == s) -+ return -EINVAL; -+ s = e; -+ } -+ ithc_log_regs(ithc); -+ -+ // Execute the command. -+ switch (cmd[0]) { -+ case 'x': // reset -+ ithc_reset(ithc); -+ break; -+ case 'w': // write register: offset mask value -+ if (n != 3 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", -+ a[0], a[2], a[1]); -+ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); -+ break; -+ case 'r': // read register: offset -+ if (n != 1 || (a[0] & 3)) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], -+ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); -+ break; -+ case 's': // spi command: cmd offset len data... -+ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ // set touch cfg: s 6 12 4 XX -+ if (n < 3 || a[2] > (n - 3) * 4) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); -+ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) -+ for (u32 i = 0; i < (a[2] + 3) / 4; i++) -+ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); -+ break; -+ case 'd': // dma command: cmd len data... -+ // get report descriptor: d 7 8 0 0 -+ // enable multitouch: d 3 2 0x0105 -+ if (n < 1) -+ return -EINVAL; -+ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); -+ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; -+ if (ithc_dma_tx(ithc, &data)) -+ pci_err(ithc->pci, "dma tx failed\n"); -+ break; -+ default: -+ return -EINVAL; -+ } -+ ithc_log_regs(ithc); -+ return len; -+} -+ -+static struct dentry *dbg_dir; -+ -+void __init ithc_debug_init_module(void) -+{ -+ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); -+ if (IS_ERR(d)) -+ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); -+ else -+ dbg_dir = d; -+} -+ -+void __exit ithc_debug_exit_module(void) -+{ -+ debugfs_remove_recursive(dbg_dir); -+ dbg_dir = NULL; -+} -+ -+static const struct file_operations ithc_debugfops_cmd = { -+ .owner = THIS_MODULE, -+ .write = ithc_debugfs_cmd_write, -+}; -+ -+static void ithc_debugfs_devres_release(struct device *dev, void *res) -+{ -+ struct dentry **dbgm = res; -+ debugfs_remove_recursive(*dbgm); -+} -+ -+int ithc_debug_init_device(struct ithc *ithc) -+{ -+ if (!dbg_dir) -+ return -ENOENT; -+ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); -+ if (!dbgm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, dbgm); -+ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); -+ if (IS_ERR(dbg)) -+ return PTR_ERR(dbg); -+ *dbgm = dbg; -+ -+ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); -+ if (IS_ERR(cmd)) -+ return PTR_ERR(cmd); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h -new file mode 100644 -index 000000000000..38c53d916bdb ---- /dev/null -+++ b/drivers/hid/ithc/ithc-debug.h -@@ -0,0 +1,7 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+void ithc_debug_init_module(void); -+void ithc_debug_exit_module(void); -+int ithc_debug_init_device(struct ithc *ithc); -+void ithc_log_regs(struct ithc *ithc); -+ -diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c -new file mode 100644 -index 000000000000..bf4eab33062b ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.c -@@ -0,0 +1,312 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. -+// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. -+// This allows each data buffer to consist of multiple non-contiguous blocks of memory. -+ -+static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, -+ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) -+{ -+ p->num_pages = num_pages; -+ p->dir = dir; -+ // We allocate enough space to have one PRD per data buffer page, however if the data -+ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so -+ // some will remain unused (which is fine). -+ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); -+ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); -+ if (!p->addr) -+ return -ENOMEM; -+ if (p->dma_addr & (PAGE_SIZE - 1)) -+ return -EFAULT; -+ return 0; -+} -+ -+// Devres managed sg_table wrapper. -+struct ithc_sg_table { -+ void *addr; -+ struct sg_table sgt; -+ enum dma_data_direction dir; -+}; -+static void ithc_dma_sgtable_free(struct sg_table *sgt) -+{ -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_sg(sgt, sg, i) { -+ struct page *p = sg_page(sg); -+ if (p) -+ __free_page(p); -+ } -+ sg_free_table(sgt); -+} -+static void ithc_dma_data_devres_release(struct device *dev, void *res) -+{ -+ struct ithc_sg_table *sgt = res; -+ if (sgt->addr) -+ vunmap(sgt->addr); -+ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); -+ ithc_dma_sgtable_free(&sgt->sgt); -+} -+ -+static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b) -+{ -+ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be -+ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). -+ // We could use dma_alloc_noncontiguous(), however this still always allocates a single -+ // DMA mapped segment, which is more restrictive than what we need. -+ // Instead we use an sg_table of individually allocated pages. -+ struct page *pages[16]; -+ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) -+ return -EINVAL; -+ b->active_idx = -1; -+ struct ithc_sg_table *sgt = devres_alloc( -+ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); -+ if (!sgt) -+ return -ENOMEM; -+ sgt->dir = prds->dir; -+ -+ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { -+ struct scatterlist *sg; -+ int i; -+ bool ok = true; -+ for_each_sgtable_sg(&sgt->sgt, sg, i) { -+ // NOTE: don't need __GFP_DMA for PCI DMA -+ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); -+ if (!p) { -+ ok = false; -+ break; -+ } -+ sg_set_page(sg, p, PAGE_SIZE, 0); -+ } -+ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { -+ devres_add(&ithc->pci->dev, sgt); -+ b->sgt = &sgt->sgt; -+ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); -+ if (!b->addr) -+ return -ENOMEM; -+ return 0; -+ } -+ ithc_dma_sgtable_free(&sgt->sgt); -+ } -+ devres_free(sgt); -+ return -ENOMEM; -+} -+ -+static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Give a buffer to the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ if (b->active_idx >= 0) { -+ pci_err(ithc->pci, "buffer already active\n"); -+ return -EINVAL; -+ } -+ b->active_idx = idx; -+ if (prds->dir == DMA_TO_DEVICE) { -+ // TX buffer: Caller should have already filled the data buffer, so just fill -+ // the PRD and flush. -+ // (TODO: Support multi-page TX buffers. So far no device seems to use or need -+ // these though.) -+ if (b->data_size > PAGE_SIZE) -+ return -EINVAL; -+ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; -+ prd->size = b->data_size | PRD_FLAG_END; -+ flush_kernel_vmap_range(b->addr, b->data_size); -+ } else if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Reset PRDs. -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ prd->addr = sg_dma_address(sg) >> 10; -+ prd->size = sg_dma_len(sg); -+ prd++; -+ } -+ prd[-1].size |= PRD_FLAG_END; -+ } -+ dma_wmb(); // for the prds -+ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, -+ struct ithc_dma_data_buffer *b, unsigned int idx) -+{ -+ // Take a buffer from the THC. -+ struct ithc_phys_region_desc *prd = prds->addr; -+ prd += idx * prds->num_pages; -+ // This is purely a sanity check. We don't strictly need the idx parameter for this -+ // function, because it should always be the same as active_idx, unless we have a bug. -+ if (b->active_idx != idx) { -+ pci_err(ithc->pci, "wrong buffer index\n"); -+ return -EINVAL; -+ } -+ b->active_idx = -1; -+ if (prds->dir == DMA_FROM_DEVICE) { -+ // RX buffer: Calculate actual received data size from PRDs. -+ dma_rmb(); // for the prds -+ b->data_size = 0; -+ struct scatterlist *sg; -+ int i; -+ for_each_sgtable_dma_sg(b->sgt, sg, i) { -+ unsigned int size = prd->size; -+ b->data_size += size & PRD_SIZE_MASK; -+ if (size & PRD_FLAG_END) -+ break; -+ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { -+ pci_err(ithc->pci, "truncated prd\n"); -+ break; -+ } -+ prd++; -+ } -+ invalidate_kernel_vmap_range(b->addr, b->data_size); -+ } -+ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); -+ return 0; -+} -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_init(&rx->mutex); -+ -+ // Allocate buffers. -+ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", -+ NUM_RX_BUF, ithc->max_rx_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); -+ -+ // Init registers. -+ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); -+ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); -+ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); -+ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); -+ u8 head = readb(&ithc->regs->dma_rx[channel].head); -+ if (head) { -+ pci_err(ithc->pci, "head is nonzero (%u)\n", head); -+ return -EIO; -+ } -+ -+ // Init buffers. -+ for (unsigned int i = 0; i < NUM_RX_BUF; i++) -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); -+ -+ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); -+ return 0; -+} -+ -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) -+{ -+ bitsb_set(&ithc->regs->dma_rx[channel].control, -+ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, -+ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); -+} -+ -+int ithc_dma_tx_init(struct ithc *ithc) -+{ -+ struct ithc_dma_tx *tx = &ithc->dma_tx; -+ mutex_init(&tx->mutex); -+ -+ // Allocate buffers. -+ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; -+ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", -+ ithc->max_tx_size, num_pages); -+ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); -+ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); -+ -+ // Init registers. -+ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); -+ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); -+ -+ // Init buffers. -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ return 0; -+} -+ -+static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) -+{ -+ // Process all filled RX buffers from the ringbuffer. -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ unsigned int n = rx->num_received; -+ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); -+ while (1) { -+ u8 tail = n % NUM_RX_BUF; -+ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); -+ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); -+ // ringbuffer is full if tail_wrap == head_wrap -+ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG -+ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) -+ return 0; -+ -+ // take the buffer that the device just filled -+ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); -+ rx->num_received = ++n; -+ -+ // process data -+ struct ithc_data d; -+ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) -+ (ithc, b->addr, b->data_size, &d) < 0) { -+ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", -+ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); -+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, -+ b->addr, min(b->data_size, 0x400u), 0); -+ } else { -+ ithc_hid_process_data(ithc, &d); -+ } -+ -+ // give the buffer back to the device -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); -+ } -+} -+int ithc_dma_rx(struct ithc *ithc, u8 channel) -+{ -+ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; -+ mutex_lock(&rx->mutex); -+ int ret = ithc_dma_rx_unlocked(ithc, channel); -+ mutex_unlock(&rx->mutex); -+ return ret; -+} -+ -+static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) -+{ -+ // Send a single TX buffer to the THC. -+ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); -+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ -+ // Fill the TX buffer with header and data. -+ ssize_t sz; -+ if (data->type == ITHC_DATA_RAW) { -+ sz = min(data->size, ithc->max_tx_size); -+ memcpy(ithc->dma_tx.buf.addr, data->data, sz); -+ } else { -+ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) -+ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); -+ } -+ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; -+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); -+ if (sz < 0) { -+ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", -+ data->type, data->size, (int)sz); -+ return -EINVAL; -+ } -+ -+ // Let the THC process the buffer. -+ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); -+ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); -+ return 0; -+} -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) -+{ -+ mutex_lock(&ithc->dma_tx.mutex); -+ int ret = ithc_dma_tx_unlocked(ithc, data); -+ mutex_unlock(&ithc->dma_tx.mutex); -+ return ret; -+} -+ -diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h -new file mode 100644 -index 000000000000..1749a5819b3e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-dma.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define PRD_SIZE_MASK 0xffffff -+#define PRD_FLAG_END 0x1000000 -+#define PRD_FLAG_SUCCESS 0x2000000 -+#define PRD_FLAG_ERROR 0x4000000 -+ -+struct ithc_phys_region_desc { -+ u64 addr; // physical addr/1024 -+ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds -+ u32 unused; -+}; -+ -+struct ithc_dma_prd_buffer { -+ void *addr; -+ dma_addr_t dma_addr; -+ u32 size; -+ u32 num_pages; // per data buffer -+ enum dma_data_direction dir; -+}; -+ -+struct ithc_dma_data_buffer { -+ void *addr; -+ struct sg_table *sgt; -+ int active_idx; -+ u32 data_size; -+}; -+ -+struct ithc_dma_tx { -+ struct mutex mutex; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer buf; -+}; -+ -+struct ithc_dma_rx { -+ struct mutex mutex; -+ u32 num_received; -+ struct ithc_dma_prd_buffer prds; -+ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; -+}; -+ -+int ithc_dma_rx_init(struct ithc *ithc, u8 channel); -+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); -+int ithc_dma_tx_init(struct ithc *ithc); -+int ithc_dma_rx(struct ithc *ithc, u8 channel); -+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); -+ -diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c -new file mode 100644 -index 000000000000..065646ab499e ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.c -@@ -0,0 +1,207 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+static int ithc_hid_start(struct hid_device *hdev) { return 0; } -+static void ithc_hid_stop(struct hid_device *hdev) { } -+static int ithc_hid_open(struct hid_device *hdev) { return 0; } -+static void ithc_hid_close(struct hid_device *hdev) { } -+ -+static int ithc_hid_parse(struct hid_device *hdev) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; -+ WRITE_ONCE(ithc->hid.parse_done, false); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); -+ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), -+ msecs_to_jiffies(200))) { -+ ithc_log_regs(ithc); -+ return 0; -+ } -+ if (retries > 5) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "failed to read report descriptor\n"); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -+ } -+} -+ -+static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -+ size_t len, unsigned char rtype, int reqtype) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ if (!buf || !len) -+ return -EINVAL; -+ -+ struct ithc_data d = { .size = len, .data = buf }; -+ buf[0] = reportnum; -+ -+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_OUTPUT_REPORT; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_SET_FEATURE; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -+ d.type = ITHC_DATA_GET_FEATURE; -+ d.data = &reportnum; -+ d.size = 1; -+ -+ // Prepare for response. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = buf; -+ ithc->hid.get_feature_size = len; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ -+ // Transmit 'get feature' request. -+ int r = CHECK(ithc_dma_tx, ithc, &d); -+ if (!r) { -+ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, -+ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); -+ if (!r) -+ r = -ETIMEDOUT; -+ else if (r < 0) -+ r = -EINTR; -+ else -+ r = 0; -+ } -+ -+ // If everything went ok, the buffer has been filled with the response data. -+ // Return the response size. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = NULL; -+ if (!r) -+ r = ithc->hid.get_feature_size; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ return r; -+ } -+ -+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -+ rtype, reqtype, reportnum); -+ return -EINVAL; -+} -+ -+// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to -+// cast away the const to avoid a compiler warning... -+#define NOCONST(x) ((void *)x) -+ -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) -+{ -+ WARN_ON(!ithc->hid.dev); -+ if (!ithc->hid.dev) -+ return; -+ -+ switch (d->type) { -+ -+ case ITHC_DATA_IGNORE: -+ return; -+ -+ case ITHC_DATA_ERROR: -+ CHECK(ithc_reset, ithc); -+ return; -+ -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ // Response to the report descriptor request sent by ithc_hid_parse(). -+ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); -+ WRITE_ONCE(ithc->hid.parse_done, true); -+ wake_up(&ithc->hid.wait_parse); -+ return; -+ -+ case ITHC_DATA_INPUT_REPORT: -+ { -+ // Standard HID input report. -+ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); -+ if (r < 0) { -+ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", -+ r, d->size, d->size ? *(u8 *)d->data : 0); -+ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, -+ d->data, min(d->size, 0x400u), 0); -+ } -+ return; -+ } -+ -+ case ITHC_DATA_GET_FEATURE: -+ { -+ // Response to a 'get feature' request sent by ithc_hid_raw_request(). -+ bool done = false; -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ if (ithc->hid.get_feature_buf) { -+ if (d->size < ithc->hid.get_feature_size) -+ ithc->hid.get_feature_size = d->size; -+ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); -+ ithc->hid.get_feature_buf = NULL; -+ done = true; -+ } -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ if (done) { -+ wake_up(&ithc->hid.wait_get_feature); -+ } else { -+ // Received data without a matching request, or the request already -+ // timed out. (XXX What's the correct thing to do here?) -+ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, -+ NOCONST(d->data), d->size, 1); -+ } -+ return; -+ } -+ -+ default: -+ pci_err(ithc->pci, "unhandled data type %i\n", d->type); -+ return; -+ } -+} -+ -+static struct hid_ll_driver ithc_ll_driver = { -+ .start = ithc_hid_start, -+ .stop = ithc_hid_stop, -+ .open = ithc_hid_open, -+ .close = ithc_hid_close, -+ .parse = ithc_hid_parse, -+ .raw_request = ithc_hid_raw_request, -+}; -+ -+static void ithc_hid_devres_release(struct device *dev, void *res) -+{ -+ struct hid_device **hidm = res; -+ if (*hidm) -+ hid_destroy_device(*hidm); -+} -+ -+int ithc_hid_init(struct ithc *ithc) -+{ -+ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -+ if (!hidm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, hidm); -+ struct hid_device *hid = hid_allocate_device(); -+ if (IS_ERR(hid)) -+ return PTR_ERR(hid); -+ *hidm = hid; -+ -+ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -+ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -+ hid->ll_driver = &ithc_ll_driver; -+ hid->bus = BUS_PCI; -+ hid->vendor = ithc->vendor_id; -+ hid->product = ithc->product_id; -+ hid->version = 0x100; -+ hid->dev.parent = &ithc->pci->dev; -+ hid->driver_data = ithc; -+ -+ ithc->hid.dev = hid; -+ -+ init_waitqueue_head(&ithc->hid.wait_parse); -+ init_waitqueue_head(&ithc->hid.wait_get_feature); -+ mutex_init(&ithc->hid.get_feature_mutex); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h -new file mode 100644 -index 000000000000..599eb912c8c8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+enum ithc_data_type { -+ ITHC_DATA_IGNORE, -+ ITHC_DATA_RAW, -+ ITHC_DATA_ERROR, -+ ITHC_DATA_REPORT_DESCRIPTOR, -+ ITHC_DATA_INPUT_REPORT, -+ ITHC_DATA_OUTPUT_REPORT, -+ ITHC_DATA_GET_FEATURE, -+ ITHC_DATA_SET_FEATURE, -+}; -+ -+struct ithc_data { -+ enum ithc_data_type type; -+ u32 size; -+ const void *data; -+}; -+ -+struct ithc_hid { -+ struct hid_device *dev; -+ bool parse_done; -+ wait_queue_head_t wait_parse; -+ wait_queue_head_t wait_get_feature; -+ struct mutex get_feature_mutex; -+ void *get_feature_buf; -+ size_t get_feature_size; -+}; -+ -+int ithc_hid_init(struct ithc *ithc); -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); -+ -diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c -new file mode 100644 -index 000000000000..8883987fb352 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.c -@@ -0,0 +1,254 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) -+#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) -+ -+#define DEVCFG_TOUCH_MASK 0x3f -+#define DEVCFG_TOUCH_ENABLE BIT(0) -+#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) -+#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) -+#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) -+#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) -+ -+#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" -+ -+#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) -+#define DEVCFG_SPI_CLKDIV_8 BIT(4) -+#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) -+#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) -+#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) -+#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) -+#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) -+#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat -+#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) -+#define DEVCFG_SPI_UNKNOWN_25 BIT(25) -+#define DEVCFG_SPI_UNKNOWN_26 BIT(26) -+#define DEVCFG_SPI_UNKNOWN_27 BIT(27) -+#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this -+#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? -+ -+struct ithc_device_config { // (Example values are from an SP7+.) -+ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) -+ u32 error; // 04 = 0x00000000 -+ u32 dma_buf_sizes; // 08 = 0x000a00ff -+ u32 touch_cfg; // 0c = 0x0000001c -+ u32 touch_state; // 10 = 0x0000001c -+ u32 device_id; // 14 = 0x43495424 = "$TIC" -+ u32 spi_config; // 18 = 0xfda00a2e -+ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. -+ u16 product_id; // 1e = 0x0c1a -+ u32 revision; // 20 = 0x00000001 -+ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) -+ u32 command; // 28 = 0x00000000 -+ u32 fw_mode; // 2c = 0x00000000 (for fw update?) -+ u32 _unknown_30; // 30 = 0x00000000 -+ u8 eds_minor_ver; // 34 = 0x5e -+ u8 eds_major_ver; // 35 = 0x03 -+ u8 interface_rev; // 36 = 0x04 -+ u8 eu_kernel_ver; // 37 = 0x04 -+ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) -+ u32 _unknown_3c; // 3c = 0x00000002 -+}; -+static_assert(sizeof(struct ithc_device_config) == 64); -+ -+#define RX_CODE_INPUT_REPORT 3 -+#define RX_CODE_FEATURE_REPORT 4 -+#define RX_CODE_REPORT_DESCRIPTOR 5 -+#define RX_CODE_RESET 7 -+ -+#define TX_CODE_SET_FEATURE 3 -+#define TX_CODE_GET_FEATURE 4 -+#define TX_CODE_OUTPUT_REPORT 5 -+#define TX_CODE_GET_REPORT_DESCRIPTOR 7 -+ -+static int ithc_set_device_enabled(struct ithc *ithc, bool enable) -+{ -+ u32 x = ithc->legacy_touch_cfg = -+ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | -+ DEVCFG_TOUCH_HID_REPORT_ENABLE | -+ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); -+ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -+ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); -+} -+ -+int ithc_legacy_init(struct ithc *ithc) -+{ -+ // Since we don't yet know which SPI config the device wants, use default speed and mode -+ // initially for reading config data. -+ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); -+ -+ // Setting the following bit seems to make reading the config more reliable. -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ // Setting this bit may be necessary on ADL devices. -+ switch (ithc->pci->device) { -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); -+ break; -+ } -+ -+ // Take the touch device out of reset. -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -+ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) -+ break; -+ if (retries > 5) { -+ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", -+ readl(&ithc->regs->irq_cause)); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ if (msleep_interruptible(1000)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ -+ // Read configuration data. -+ u32 spi_cfg; -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ struct ithc_device_config config = { 0 }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); -+ u32 *p = (void *)&config; -+ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { -+ spi_cfg = config.spi_config; -+ ithc->vendor_id = config.vendor_id; -+ ithc->product_id = config.product_id; -+ ithc->product_rev = config.revision; -+ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); -+ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); -+ ithc->legacy_touch_cfg = config.touch_cfg; -+ ithc->have_config = true; -+ break; -+ } -+ if (retries > 10) { -+ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -+ config.device_id); -+ return -EIO; -+ } -+ pci_warn(ithc->pci, "failed to read config, retrying\n"); -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ // Apply SPI config and enable touch device. -+ CHECK_RET(ithc_set_spi_config, ithc, -+ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, -+ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : -+ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : -+ SPI_MODE_SINGLE, -+ SPI_MODE_SINGLE); -+ CHECK_RET(ithc_set_device_enabled, ithc, true); -+ ithc_log_regs(ithc); -+ return 0; -+} -+ -+void ithc_legacy_exit(struct ithc *ithc) -+{ -+ CHECK(ithc_set_device_enabled, ithc, false); -+} -+ -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct { -+ u32 code; -+ u32 data_size; -+ u32 _unknown[14]; -+ } *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // Note: RX data is not padded, even though TX data must be padded. -+ if (len != sizeof(*hdr) + hdr->data_size) -+ return -EMSGSIZE; -+ -+ dest->data = hdr + 1; -+ dest->size = hdr->data_size; -+ -+ switch (hdr->code) { -+ case RX_CODE_RESET: -+ // The THC sends a reset request when we need to reinitialize the device. -+ // This usually only happens if we send an invalid command or put the device -+ // in a bad state. -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case RX_CODE_REPORT_DESCRIPTOR: -+ // The descriptor is preceded by 8 nul bytes. -+ if (hdr->data_size < 8) -+ return -ENODATA; -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = (char *)(hdr + 1) + 8; -+ dest->size = hdr->data_size - 8; -+ return 0; -+ case RX_CODE_INPUT_REPORT: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ return 0; -+ case RX_CODE_FEATURE_REPORT: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct { -+ u32 code; -+ u32 data_size; -+ } *hdr = dest; -+ -+ size_t src_size = src->size; -+ const void *src_data = src->data; -+ const u64 get_report_desc_data = 0; -+ u32 code; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ code = TX_CODE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ code = TX_CODE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ code = TX_CODE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ code = TX_CODE_GET_REPORT_DESCRIPTOR; -+ src_size = sizeof(get_report_desc_data); -+ src_data = &get_report_desc_data; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->code = code; -+ hdr->data_size = src_size; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h -new file mode 100644 -index 000000000000..28d692462072 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.h -@@ -0,0 +1,8 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+int ithc_legacy_init(struct ithc *ithc); -+void ithc_legacy_exit(struct ithc *ithc); -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -new file mode 100644 -index 000000000000..ac56c253674b ---- /dev/null -+++ b/drivers/hid/ithc/ithc-main.c -@@ -0,0 +1,431 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+MODULE_DESCRIPTION("Intel Touch Host Controller driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+ -+static const struct pci_device_id ithc_pci_tbl[] = { -+ { -+ .vendor = PCI_VENDOR_ID_INTEL, -+ .device = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subdevice = PCI_ANY_ID, -+ .class = PCI_CLASS_INPUT_PEN << 8, -+ .class_mask = ~0, -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); -+ -+// Module parameters -+ -+static bool ithc_use_polling = false; -+module_param_named(poll, ithc_use_polling, bool, 0); -+MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); -+ -+// Since all known devices seem to use only channel 1, by default we disable channel 0. -+static bool ithc_use_rx0 = false; -+module_param_named(rx0, ithc_use_rx0, bool, 0); -+MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); -+ -+static bool ithc_use_rx1 = true; -+module_param_named(rx1, ithc_use_rx1, bool, 0); -+MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); -+ -+static int ithc_active_ltr_us = -1; -+module_param_named(activeltr, ithc_active_ltr_us, int, 0); -+MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); -+ -+static int ithc_idle_ltr_us = -1; -+module_param_named(idleltr, ithc_idle_ltr_us, int, 0); -+MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); -+ -+static unsigned int ithc_idle_delay_ms = 1000; -+module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); -+MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); -+ -+static bool ithc_log_regs_enabled = false; -+module_param_named(logregs, ithc_log_regs_enabled, bool, 0); -+MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); -+ -+// Interrupts/polling -+ -+static void ithc_disable_interrupts(struct ithc *ithc) -+{ -+ writel(0, &ithc->regs->error_control); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); -+} -+ -+static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) -+{ -+ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, -+ &ithc->regs->dma_rx[channel].status); -+} -+ -+static void ithc_clear_interrupts(struct ithc *ithc) -+{ -+ writel(0xffffffff, &ithc->regs->error_flags); -+ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, -+ &ithc->regs->dma_tx.status); -+} -+ -+static void ithc_idle_timer_callback(struct timer_list *t) -+{ -+ struct ithc *ithc = container_of(t, struct ithc, idle_timer); -+ ithc_set_ltr_idle(ithc); -+} -+ -+static void ithc_process(struct ithc *ithc) -+{ -+ ithc_log_regs(ithc); -+ -+ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. -+ // It does not appear to automatically go back to idle, so we switch it back after a delay. -+ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); -+ -+ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; -+ -+ // Read and clear error bits -+ u32 err = readl(&ithc->regs->error_flags); -+ if (err) { -+ writel(err, &ithc->regs->error_flags); -+ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "error flags: 0x%08x\n", err); -+ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); -+ } -+ -+ // Process DMA rx -+ if (ithc_use_rx0) { -+ ithc_clear_dma_rx_interrupts(ithc, 0); -+ if (rx0) -+ ithc_dma_rx(ithc, 0); -+ } -+ if (ithc_use_rx1) { -+ ithc_clear_dma_rx_interrupts(ithc, 1); -+ if (rx1) -+ ithc_dma_rx(ithc, 1); -+ } -+ -+ ithc_log_regs(ithc); -+} -+ -+static irqreturn_t ithc_interrupt_thread(int irq, void *arg) -+{ -+ struct ithc *ithc = arg; -+ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", -+ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), -+ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), -+ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), -+ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), -+ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); -+ ithc_process(ithc); -+ return IRQ_HANDLED; -+} -+ -+static int ithc_poll_thread(void *arg) -+{ -+ struct ithc *ithc = arg; -+ unsigned int sleep = 100; -+ while (!kthread_should_stop()) { -+ u32 n = ithc->dma_rx[1].num_received; -+ ithc_process(ithc); -+ // Decrease polling interval to 20ms if we received data, otherwise slowly -+ // increase it up to 200ms. -+ sleep = n != ithc->dma_rx[1].num_received ? 20 -+ : min(200u, sleep + (sleep >> 4) + 1); -+ msleep_interruptible(sleep); -+ } -+ return 0; -+} -+ -+// Device initialization and shutdown -+ -+static void ithc_disable(struct ithc *ithc) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); -+ ithc_disable_interrupts(ithc); -+ ithc_clear_interrupts(ithc); -+} -+ -+static int ithc_init_device(struct ithc *ithc) -+{ -+ // Read ACPI config for QuickSPI mode -+ struct ithc_acpi_config cfg = { 0 }; -+ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); -+ if (!cfg.has_config) -+ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); -+ else -+ ithc_print_acpi_config(ithc, &cfg); -+ ithc->use_quickspi = cfg.has_config; -+ -+ // Shut down device -+ ithc_log_regs(ithc); -+ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; -+ ithc_disable(ithc); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); -+ ithc_log_regs(ithc); -+ -+ // If the device was previously enabled, wait a bit to make sure it's fully shut down. -+ if (was_enabled) -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ -+ // Set Latency Tolerance Reporting config. The device will automatically -+ // apply these values depending on whether it is active or idle. -+ // If active value is too high, DMA buffer data can become truncated. -+ // By default, we set the active LTR value to 50us, and idle to 100ms. -+ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 -+ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 -+ : 50 * 1000; -+ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 -+ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 -+ : 100 * 1000 * 1000; -+ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); -+ -+ if (ithc->use_quickspi) -+ CHECK_RET(ithc_quickspi_init, ithc, &cfg); -+ else -+ CHECK_RET(ithc_legacy_init, ithc); -+ -+ return 0; -+} -+ -+int ithc_reset(struct ithc *ithc) -+{ -+ // FIXME This should probably do devres_release_group()+ithc_start(). -+ // But because this is called during DMA processing, that would have to be done -+ // asynchronously (schedule_work()?). And with extra locking? -+ pci_err(ithc->pci, "reset\n"); -+ CHECK(ithc_init_device, ithc); -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "reset completed\n"); -+ return 0; -+} -+ -+static void ithc_stop(void *res) -+{ -+ struct ithc *ithc = res; -+ pci_dbg(ithc->pci, "stopping\n"); -+ ithc_log_regs(ithc); -+ -+ if (ithc->poll_thread) -+ CHECK(kthread_stop, ithc->poll_thread); -+ if (ithc->irq >= 0) -+ disable_irq(ithc->irq); -+ if (ithc->use_quickspi) -+ ithc_quickspi_exit(ithc); -+ else -+ ithc_legacy_exit(ithc); -+ ithc_disable(ithc); -+ del_timer_sync(&ithc->idle_timer); -+ -+ // Clear DMA config. -+ for (unsigned int i = 0; i < 2; i++) { -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); -+ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); -+ writeb(0, &ithc->regs->dma_rx[i].num_bufs); -+ writeb(0, &ithc->regs->dma_rx[i].num_prds); -+ } -+ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); -+ writeb(0, &ithc->regs->dma_tx.num_prds); -+ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "stopped\n"); -+} -+ -+static void ithc_clear_drvdata(void *res) -+{ -+ struct pci_dev *pci = res; -+ pci_set_drvdata(pci, NULL); -+} -+ -+static int ithc_start(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "starting\n"); -+ if (pci_get_drvdata(pci)) { -+ pci_err(pci, "device already initialized\n"); -+ return -EINVAL; -+ } -+ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) -+ return -ENOMEM; -+ -+ // Allocate/init main driver struct. -+ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); -+ if (!ithc) -+ return -ENOMEM; -+ ithc->irq = -1; -+ ithc->pci = pci; -+ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); -+ pci_set_drvdata(pci, ithc); -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); -+ if (ithc_log_regs_enabled) -+ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); -+ -+ // PCI initialization. -+ CHECK_RET(pcim_enable_device, pci); -+ pci_set_master(pci); -+ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); -+ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); -+ CHECK_RET(pci_set_power_state, pci, PCI_D0); -+ ithc->regs = pcim_iomap_table(pci)[0]; -+ -+ // Allocate IRQ. -+ if (!ithc_use_polling) { -+ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); -+ ithc->irq = CHECK(pci_irq_vector, pci, 0); -+ if (ithc->irq < 0) -+ return ithc->irq; -+ } -+ -+ // Initialize THC and touch device. -+ CHECK_RET(ithc_init_device, ithc); -+ -+ // Initialize HID and DMA. -+ CHECK_RET(ithc_hid_init, ithc); -+ if (ithc_use_rx0) -+ CHECK_RET(ithc_dma_rx_init, ithc, 0); -+ if (ithc_use_rx1) -+ CHECK_RET(ithc_dma_rx_init, ithc, 1); -+ CHECK_RET(ithc_dma_tx_init, ithc); -+ -+ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); -+ -+ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are -+ // disabled BEFORE the buffers are freed. -+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); -+ -+ // Start polling/IRQ. -+ if (ithc_use_polling) { -+ pci_info(pci, "using polling instead of irq\n"); -+ // Use a thread instead of simple timer because we want to be able to sleep. -+ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); -+ if (IS_ERR(ithc->poll_thread)) { -+ int err = PTR_ERR(ithc->poll_thread); -+ ithc->poll_thread = NULL; -+ return err; -+ } -+ } else { -+ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, -+ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); -+ } -+ -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); -+ -+ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, -+ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. -+ CHECK_RET(hid_add_device, ithc->hid.dev); -+ -+ CHECK(ithc_debug_init_device, ithc); -+ -+ ithc_set_ltr_idle(ithc); -+ -+ pci_dbg(pci, "started\n"); -+ return 0; -+} -+ -+static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) -+{ -+ pci_dbg(pci, "device probe\n"); -+ return ithc_start(pci); -+} -+ -+static void ithc_remove(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "device remove\n"); -+ // all cleanup is handled by devres -+} -+ -+// For suspend/resume, we just deinitialize and reinitialize everything. -+// TODO It might be cleaner to keep the HID device around, however we would then have to signal -+// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set -+// feature' requests. Hidraw does not seem to have a facility to do that. -+static int ithc_suspend(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm suspend\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_resume(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm resume\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_freeze(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm freeze\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; -+} -+ -+static int ithc_thaw(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm thaw\n"); -+ return ithc_start(pci); -+} -+ -+static int ithc_restore(struct device *dev) -+{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm restore\n"); -+ return ithc_start(pci); -+} -+ -+static struct pci_driver ithc_driver = { -+ .name = DEVNAME, -+ .id_table = ithc_pci_tbl, -+ .probe = ithc_probe, -+ .remove = ithc_remove, -+ .driver.pm = &(const struct dev_pm_ops) { -+ .suspend = ithc_suspend, -+ .resume = ithc_resume, -+ .freeze = ithc_freeze, -+ .thaw = ithc_thaw, -+ .restore = ithc_restore, -+ }, -+ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, -+}; -+ -+static int __init ithc_init(void) -+{ -+ ithc_debug_init_module(); -+ return pci_register_driver(&ithc_driver); -+} -+ -+static void __exit ithc_exit(void) -+{ -+ pci_unregister_driver(&ithc_driver); -+ ithc_debug_exit_module(); -+} -+ -+module_init(ithc_init); -+module_exit(ithc_exit); -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c -new file mode 100644 -index 000000000000..e2d1690b8cf8 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.c -@@ -0,0 +1,607 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+// Some public THC/QuickSPI documentation can be found in: -+// - Intel Firmware Support Package repo: https://github.com/intel/FSP -+// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 -+ -+#include "ithc.h" -+ -+static const guid_t guid_hidspi = -+ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); -+static const guid_t guid_thc_quickspi = -+ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); -+static const guid_t guid_thc_ltr = -+ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); -+ -+// TODO The HIDSPI spec says revision should be 3. Should we try both? -+#define DSM_REV 2 -+ -+struct hidspi_header { -+ u8 type; -+ u16 len; -+ u8 id; -+} __packed; -+static_assert(sizeof(struct hidspi_header) == 4); -+ -+#define HIDSPI_INPUT_TYPE_DATA 1 -+#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 -+#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 -+#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 -+#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 -+#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 -+#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 -+#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 -+#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 -+ -+#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 -+#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 -+#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 -+#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 -+#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 -+#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 -+#define HIDSPI_OUTPUT_TYPE_COMMAND 7 -+ -+struct hidspi_device_descriptor { -+ u16 wDeviceDescLength; -+ u16 bcdVersion; -+ u16 wReportDescLength; -+ u16 wMaxInputLength; -+ u16 wMaxOutputLength; -+ u16 wMaxFragmentLength; -+ u16 wVendorID; -+ u16 wProductID; -+ u16 wVersionID; -+ u16 wFlags; -+ u32 dwReserved; -+}; -+static_assert(sizeof(struct hidspi_device_descriptor) == 24); -+ -+static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_INTEGER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); -+ *dest = (u32)o->integer.value; -+ ACPI_FREE(o); -+ return 1; -+} -+ -+static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) -+{ -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); -+ if (!o) -+ return 0; -+ if (o->type != ACPI_TYPE_BUFFER) { -+ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", -+ guid, func, o->type); -+ ACPI_FREE(o); -+ return -1; -+ } -+ if (o->buffer.length != len) { -+ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", -+ guid, func, o->buffer.length, len); -+ ACPI_FREE(o); -+ return -1; -+ } -+ memcpy(dest, o->buffer.pointer, len); -+ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); -+ ACPI_FREE(o); -+ return 1; -+} -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) -+{ -+ int r; -+ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); -+ -+ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); -+ if (!cfg->has_config) -+ return 0; -+ -+ // HIDSPI settings -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_header_address = r > 0; -+ if (r > 0 && cfg->input_report_header_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", -+ cfg->input_report_header_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_input_report_body_address = r > 0; -+ if (r > 0 && cfg->input_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", -+ cfg->input_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); -+ if (r < 0) -+ return r; -+ cfg->has_output_report_body_address = r > 0; -+ if (r > 0 && cfg->output_report_body_address > 0xffffff) { -+ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", -+ cfg->output_report_body_address); -+ return -1; -+ } -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_read_opcode = r > 0; -+ -+ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); -+ if (r < 0) -+ return r; -+ cfg->has_write_opcode = r > 0; -+ -+ u32 flags; -+ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); -+ if (r < 0) -+ return r; -+ cfg->has_read_mode = cfg->has_write_mode = r > 0; -+ if (r > 0) { -+ cfg->read_mode = (flags >> 14) & 3; -+ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; -+ } -+ -+ // Quick SPI settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); -+ if (r < 0) -+ return r; -+ cfg->has_spi_frequency = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); -+ if (r < 0) -+ return r; -+ cfg->has_limit_packet_size = r > 0; -+ -+ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); -+ if (r < 0) -+ return r; -+ cfg->has_tx_delay = r > 0; -+ if (r > 0) -+ cfg->tx_delay &= 0xffff; -+ -+ // LTR settings -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_active_ltr = r > 0; -+ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { -+ if (cfg->active_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", -+ cfg->active_ltr); -+ cfg->active_ltr = 500; -+ } -+ -+ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); -+ if (r < 0) -+ return r; -+ cfg->has_idle_ltr = r > 0; -+ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { -+ if (cfg->idle_ltr != 0xffffffff) -+ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", -+ cfg->idle_ltr); -+ cfg->idle_ltr = 500; -+ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) -+ cfg->idle_ltr = cfg->active_ltr; -+ } -+ -+ return 0; -+} -+ -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ if (!cfg->has_config) { -+ pci_info(ithc->pci, "No ACPI config"); -+ return; -+ } -+ -+ char input_report_header_address[16] = "-"; -+ if (cfg->has_input_report_header_address) -+ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); -+ char input_report_body_address[16] = "-"; -+ if (cfg->has_input_report_body_address) -+ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); -+ char output_report_body_address[16] = "-"; -+ if (cfg->has_output_report_body_address) -+ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); -+ char read_opcode[16] = "-"; -+ if (cfg->has_read_opcode) -+ sprintf(read_opcode, "0x%02x", cfg->read_opcode); -+ char write_opcode[16] = "-"; -+ if (cfg->has_write_opcode) -+ sprintf(write_opcode, "0x%02x", cfg->write_opcode); -+ char read_mode[16] = "-"; -+ if (cfg->has_read_mode) -+ sprintf(read_mode, "%i", cfg->read_mode); -+ char write_mode[16] = "-"; -+ if (cfg->has_write_mode) -+ sprintf(write_mode, "%i", cfg->write_mode); -+ char spi_frequency[16] = "-"; -+ if (cfg->has_spi_frequency) -+ sprintf(spi_frequency, "%u", cfg->spi_frequency); -+ char limit_packet_size[16] = "-"; -+ if (cfg->has_limit_packet_size) -+ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); -+ char tx_delay[16] = "-"; -+ if (cfg->has_tx_delay) -+ sprintf(tx_delay, "%u", cfg->tx_delay); -+ char active_ltr[16] = "-"; -+ if (cfg->has_active_ltr) -+ sprintf(active_ltr, "%u", cfg->active_ltr); -+ char idle_ltr[16] = "-"; -+ if (cfg->has_idle_ltr) -+ sprintf(idle_ltr, "%u", cfg->idle_ltr); -+ -+ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", -+ input_report_header_address, input_report_body_address, output_report_body_address, -+ read_opcode, write_opcode, read_mode, write_mode, -+ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); -+} -+ -+static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) -+{ -+ writeb(opcode, &ithc->regs->opcode[i].header); -+ writeb(opcode, &ithc->regs->opcode[i].single); -+ writeb(opcode, &ithc->regs->opcode[i].dual); -+ writeb(opcode, &ithc->regs->opcode[i].quad); -+} -+ -+static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); -+ -+ // SPI frequency and mode -+ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { -+ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); -+ return -EINVAL; -+ } -+ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); -+ bool clkdiv8 = clkdiv > 7; -+ if (clkdiv8) -+ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); -+ if (!clkdiv) -+ clkdiv = 1; -+ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, -+ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, -+ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); -+ -+ // SPI addresses and opcodes -+ if (cfg->has_input_report_header_address) -+ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); -+ if (cfg->has_input_report_body_address) { -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); -+ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); -+ } -+ if (cfg->has_output_report_body_address) -+ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); -+ -+ switch (ithc->pci->device) { -+ // LKF/TGL don't support QuickSPI. -+ // For ADL, opcode layout is RX/TX/unused. -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ if (cfg->has_read_opcode) { -+ set_opcode(ithc, 0, cfg->read_opcode); -+ } -+ if (cfg->has_write_opcode) { -+ set_opcode(ithc, 1, cfg->write_opcode); -+ } -+ break; -+ // For MTL, opcode layout was changed to RX/RX/TX. -+ // (RPL layout is unknown.) -+ default: -+ if (cfg->has_read_opcode) { -+ set_opcode(ithc, 0, cfg->read_opcode); -+ set_opcode(ithc, 1, cfg->read_opcode); -+ } -+ if (cfg->has_write_opcode) { -+ set_opcode(ithc, 2, cfg->write_opcode); -+ } -+ break; -+ } -+ -+ ithc_log_regs(ithc); -+ -+ // The rest... -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), -+ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | -+ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); -+ -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), -+ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | -+ QUICKSPI_CONFIG2_UNKNOWN_12(2)); -+ -+ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), -+ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); -+ -+ bitsl_set(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); -+ bitsl(&ithc->regs->quickspi_config2, -+ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | -+ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); -+ -+ return 0; -+} -+ -+static int wait_for_report(struct ithc *ithc) -+{ -+ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, -+ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); -+ -+ u32 h = readl(&ithc->regs->input_header); -+ ithc_log_regs(ithc); -+ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE -+ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { -+ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); -+ return -ENODATA; -+ } -+ return INPUT_HEADER_REPORT_LENGTH(h) * 4; -+} -+ -+static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ pci_dbg(ithc->pci, "initializing HIDSPI\n"); -+ -+ // HIDSPI initialization sequence: -+ // "1. The host shall invoke the ACPI reset method to clear the device state." -+ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); -+ if (ACPI_FAILURE(s)) { -+ pci_err(ithc->pci, "ACPI reset failed\n"); -+ return -EIO; -+ } -+ -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ -+ // "2. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing a device reset response." -+ int size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(struct hidspi_header)) { -+ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "3. The host shall read the reset response from the device at the Input Report addresses -+ // specified in ACPI." -+ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; -+ struct { -+ struct hidspi_header header; -+ union { -+ struct hidspi_device_descriptor device_desc; -+ u32 data[16]; -+ }; -+ } resp = { 0 }; -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { -+ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); -+ return -ENOMSG; -+ } -+ -+ // "4. The host shall then write an Output Report to the device at the Output Report Address -+ // specified in ACPI, requesting the Device Descriptor from the device." -+ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; -+ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); -+ -+ // "5. Within 1 second, the device shall signal an interrupt and make available to the host -+ // an input report containing the Device Descriptor." -+ size = wait_for_report(ithc); -+ if (size < 0) -+ return size; -+ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { -+ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ -+ // "6. The host shall read the Device Descriptor from the Input Report addresses specified -+ // in ACPI." -+ if (size > sizeof(resp)) { -+ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); -+ return -EMSGSIZE; -+ } -+ memset(&resp, 0, sizeof(resp)); -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); -+ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { -+ pci_err(ithc->pci, "received type %i instead of device descriptor\n", -+ resp.header.type); -+ return -ENOMSG; -+ } -+ struct hidspi_device_descriptor *d = &resp.device_desc; -+ if (resp.header.len < sizeof(*d)) { -+ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", -+ resp.header.len); -+ return -EMSGSIZE; -+ } -+ if (d->wDeviceDescLength != sizeof(*d)) { -+ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", -+ d->wDeviceDescLength); -+ return -EMSGSIZE; -+ } -+ -+ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", -+ d->bcdVersion, d->wReportDescLength, -+ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, -+ d->wVendorID, d->wProductID, d->wVersionID, -+ d->wFlags, d->dwReserved); -+ -+ ithc->vendor_id = d->wVendorID; -+ ithc->product_id = d->wProductID; -+ ithc->product_rev = d->wVersionID; -+ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, -+ d->wReportDescLength + sizeof(struct hidspi_header)); -+ ithc->max_tx_size = d->wMaxOutputLength; -+ ithc->have_config = true; -+ -+ // "7. The device and host shall then enter their "Ready" states - where the device may -+ // begin sending Input Reports, and the device shall be prepared for Output Reports from -+ // the host." -+ -+ return 0; -+} -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) -+{ -+ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); -+ -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); -+ ithc_log_regs(ithc); -+ -+ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, -+ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? -+ bitsl(&ithc->regs->quickspi_config1, -+ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); -+ -+ // TODO Do we need to set any of the following bits here? -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); -+ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); -+ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ ithc_log_regs(ithc); -+ -+ return 0; -+} -+ -+void ithc_quickspi_exit(struct ithc *ithc) -+{ -+ // TODO Should we send HIDSPI 'power off' command? -+ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; -+ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; -+ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() -+} -+ -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct hidspi_header *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // TODO Do we need to handle HIDSPI packet fragmentation? -+ if (len < sizeof(*hdr) + hdr->len) -+ return -EMSGSIZE; -+ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) -+ return -EMSGSIZE; -+ -+ switch (hdr->type) { -+ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: -+ // TODO "When the device detects an error condition, it may interrupt and make -+ // available to the host an Input Report containing an unsolicited Reset Response. -+ // After receiving an unsolicited Reset Response, the host shall initiate the -+ // request procedure from step (4) in the [HIDSPI initialization] process." -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = hdr + 1; -+ dest->size = hdr->len; -+ return 0; -+ case HIDSPI_INPUT_TYPE_DATA: -+ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ dest->data = &hdr->id; -+ dest->size = hdr->len + 1; -+ return 0; -+ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: -+ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: -+ dest->type = ITHC_DATA_IGNORE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) -+{ -+ struct hidspi_header *hdr = dest; -+ -+ size_t src_size = src->size; -+ const u8 *src_data = src->data; -+ u8 type; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; -+ src_size = 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ u8 id = 0; -+ if (src_size) { -+ id = *src_data++; -+ src_size--; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->type = type; -+ hdr->len = (u16)src_size; -+ hdr->id = id; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; -+} -+ -diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h -new file mode 100644 -index 000000000000..74d882f6b2f0 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-quickspi.h -@@ -0,0 +1,39 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+struct ithc_acpi_config { -+ bool has_config: 1; -+ bool has_input_report_header_address: 1; -+ bool has_input_report_body_address: 1; -+ bool has_output_report_body_address: 1; -+ bool has_read_opcode: 1; -+ bool has_write_opcode: 1; -+ bool has_read_mode: 1; -+ bool has_write_mode: 1; -+ bool has_spi_frequency: 1; -+ bool has_limit_packet_size: 1; -+ bool has_tx_delay: 1; -+ bool has_active_ltr: 1; -+ bool has_idle_ltr: 1; -+ u32 input_report_header_address; -+ u32 input_report_body_address; -+ u32 output_report_body_address; -+ u8 read_opcode; -+ u8 write_opcode; -+ u8 read_mode; -+ u8 write_mode; -+ u32 spi_frequency; -+ u32 limit_packet_size; -+ u32 tx_delay; // us/10 // TODO use? -+ u32 active_ltr; // ns/1024 -+ u32 idle_ltr; // ns/1024 -+}; -+ -+int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); -+void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+ -+int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); -+void ithc_quickspi_exit(struct ithc *ithc); -+int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c -new file mode 100644 -index 000000000000..c0f13506af20 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.c -@@ -0,0 +1,154 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writel((readl(reg) & ~mask) | (val & mask), reg); -+} -+ -+void bitsb(__iomem u8 *reg, u8 mask, u8 val) -+{ -+ if (val & ~mask) -+ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", -+ reg_num(reg), val, mask); -+ writeb((readb(reg) & ~mask) | (val & mask), reg); -+} -+ -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) -+{ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ u32 x; -+ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) -+{ -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ u8 x; -+ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", -+ reg_num(reg), mask, val); -+ return -ETIMEDOUT; -+ } -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "done waiting\n"); -+ return 0; -+} -+ -+static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) -+{ -+ unsigned int s = 0; -+ u64 v = *ns; -+ while (v > 0x3ff) { -+ s++; -+ v >>= 5; -+ } -+ if (s > 5) { -+ s = 5; -+ v = 0x3ff; -+ } -+ *val = v; -+ *scale = s; -+ *ns = v << (5 * s); -+} -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) -+{ -+ unsigned int active_val, active_scale, idle_val, idle_scale; -+ calc_ltr(&active_ltr_ns, &active_val, &active_scale); -+ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); -+ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", -+ active_ltr_ns, idle_ltr_ns); -+ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | -+ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | -+ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), -+ &ithc->regs->ltr_config); -+} -+ -+void ithc_set_ltr_idle(struct ithc *ithc) -+{ -+ u32 ltr = readl(&ithc->regs->ltr_config); -+ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { -+ case LTR_CONFIG_STATUS_IDLE: -+ break; -+ case LTR_CONFIG_STATUS_ACTIVE: -+ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); -+ break; -+ default: -+ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); -+ break; -+ } -+} -+ -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) -+{ -+ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) -+ return -EINVAL; -+ static const char * const modes[] = { "single", "dual", "quad" }; -+ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", -+ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), -+ modes[read_mode], modes[write_mode]); -+ bitsl(&ithc->regs->spi_config, -+ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | -+ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | -+ SPI_CONFIG_CLKDIV_8, -+ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | -+ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | -+ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); -+ return 0; -+} -+ -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) -+{ -+ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); -+ if (size > sizeof(ithc->regs->spi_cmd.data)) -+ return -EINVAL; -+ -+ // Wait if the device is still busy. -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ // Clear result flags. -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ -+ // Init SPI command data. -+ writeb(command, &ithc->regs->spi_cmd.code); -+ writew(size, &ithc->regs->spi_cmd.size); -+ writel(offset, &ithc->regs->spi_cmd.offset); -+ u32 *p = data, n = (size + 3) / 4; -+ for (u32 i = 0; i < n; i++) -+ writel(p[i], &ithc->regs->spi_cmd.data[i]); -+ -+ // Start transmission. -+ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); -+ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); -+ -+ // Read response. -+ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) -+ return -EIO; -+ if (readw(&ithc->regs->spi_cmd.size) != size) -+ return -EMSGSIZE; -+ for (u32 i = 0; i < n; i++) -+ p[i] = readl(&ithc->regs->spi_cmd.data[i]); -+ -+ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h -new file mode 100644 -index 000000000000..4f541fe533fa ---- /dev/null -+++ b/drivers/hid/ithc/ithc-regs.h -@@ -0,0 +1,211 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) -+#define LTR_CONFIG_TOGGLE BIT(1) -+#define LTR_CONFIG_ENABLE_IDLE BIT(2) -+#define LTR_CONFIG_APPLY BIT(3) -+#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) -+#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) -+#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) -+#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) -+#define LTR_CONFIG_STATUS_ACTIVE BIT(30) -+#define LTR_CONFIG_STATUS_IDLE BIT(31) -+ -+#define CONTROL_QUIESCE BIT(1) -+#define CONTROL_IS_QUIESCED BIT(2) -+#define CONTROL_NRESET BIT(3) -+#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) -+#define CONTROL_READY BIT(29) -+ -+#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) -+#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) -+#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) -+#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) -+#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) -+#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write -+#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) -+ -+#define SPI_CLK_FREQ_BASE 125000000 -+#define SPI_MODE_SINGLE 0 -+#define SPI_MODE_DUAL 1 -+#define SPI_MODE_QUAD 2 -+ -+#define ERROR_CONTROL_UNKNOWN_0 BIT(0) -+#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs -+#define ERROR_CONTROL_UNKNOWN_2 BIT(2) -+#define ERROR_CONTROL_UNKNOWN_3 BIT(3) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) -+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? -+#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs -+ -+#define ERROR_STATUS_DMA BIT(28) -+#define ERROR_STATUS_SPI BIT(30) -+ -+#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) -+#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) -+#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message -+#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) -+#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) -+#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) -+#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) -+#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) -+#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) -+#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) -+ -+#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define SPI_CMD_CONTROL_IRQ BIT(1) -+ -+#define SPI_CMD_CODE_READ 4 -+#define SPI_CMD_CODE_WRITE 6 -+ -+#define SPI_CMD_STATUS_DONE BIT(0) -+#define SPI_CMD_STATUS_ERROR BIT(1) -+#define SPI_CMD_STATUS_BUSY BIT(3) -+ -+#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define DMA_TX_CONTROL_IRQ BIT(3) -+ -+#define DMA_TX_STATUS_DONE BIT(0) -+#define DMA_TX_STATUS_ERROR BIT(1) -+#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) -+#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? -+ -+#define INPUT_HEADER_VERSION(x) ((x) & 0xf) -+#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) -+#define INPUT_HEADER_SYNC(x) ((x) >> 24) -+#define INPUT_HEADER_VERSION_VALUE 3 -+#define INPUT_HEADER_SYNC_VALUE 0x5a -+ -+#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) -+#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) -+ -+#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) -+#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) -+#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) -+#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) -+#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) -+#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) -+#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) -+#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) -+#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) -+ -+#define DMA_RX_CONTROL_ENABLE BIT(0) -+#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? -+#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only -+#define DMA_RX_CONTROL_IRQ_DATA BIT(5) -+ -+#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? -+#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? -+#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices -+ -+#define DMA_RX_WRAP_FLAG BIT(7) -+ -+#define DMA_RX_STATUS_ERROR BIT(3) -+#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) -+#define DMA_RX_STATUS_HAVE_DATA BIT(5) -+#define DMA_RX_STATUS_ENABLED BIT(8) -+ -+#define INIT_UNKNOWN_GUC_2 BIT(2) -+#define INIT_UNKNOWN_3 BIT(3) -+#define INIT_UNKNOWN_GUC_4 BIT(4) -+#define INIT_UNKNOWN_5 BIT(5) -+#define INIT_UNKNOWN_31 BIT(31) -+ -+// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. -+#define COUNTER_RESET BIT(31) -+ -+struct ithc_registers { -+ /* 0000 */ u32 _unknown_0000[5]; -+ /* 0014 */ u32 ltr_config; -+ /* 0018 */ u32 _unknown_0018[1018]; -+ /* 1000 */ u32 _unknown_1000; -+ /* 1004 */ u32 _unknown_1004; -+ /* 1008 */ u32 control_bits; -+ /* 100c */ u32 _unknown_100c; -+ /* 1010 */ u32 spi_config; -+ struct { -+ /* 1014/1018/101c */ u8 header; -+ /* 1015/1019/101d */ u8 quad; -+ /* 1016/101a/101e */ u8 dual; -+ /* 1017/101b/101f */ u8 single; -+ } opcode[3]; -+ /* 1020 */ u32 error_control; -+ /* 1024 */ u32 error_status; // write to clear -+ /* 1028 */ u32 error_flags; // write to clear -+ /* 102c */ u32 _unknown_102c[5]; -+ struct { -+ /* 1040 */ u8 control; -+ /* 1041 */ u8 code; -+ /* 1042 */ u16 size; -+ /* 1044 */ u32 status; // write to clear -+ /* 1048 */ u32 offset; -+ /* 104c */ u32 data[16]; -+ /* 108c */ u32 _unknown_108c; -+ } spi_cmd; -+ struct { -+ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1098 */ u8 control; -+ /* 1099 */ u8 _unknown_1099; -+ /* 109a */ u8 _unknown_109a; -+ /* 109b */ u8 num_prds; -+ /* 109c */ u32 status; // write to clear -+ /* 10a0 */ u32 _unknown_10a0[5]; -+ /* 10b4 */ u32 spi_addr; -+ } dma_tx; -+ /* 10b8 */ u32 spi_header_addr; -+ union { -+ /* 10bc */ u32 irq_cause; // in legacy THC mode -+ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) -+ }; -+ /* 10c0 */ u32 _unknown_10c0[8]; -+ /* 10e0 */ u32 _unknown_10e0_counters[3]; -+ /* 10ec */ u32 quickspi_config1; -+ /* 10f0 */ u32 quickspi_config2; -+ /* 10f4 */ u32 _unknown_10f4[3]; -+ struct { -+ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() -+ /* 1108/1208 */ u8 num_bufs; -+ /* 1109/1209 */ u8 num_prds; -+ /* 110a/120a */ u16 _unknown_110a; -+ /* 110c/120c */ u8 control; -+ /* 110d/120d */ u8 head; -+ /* 110e/120e */ u8 tail; -+ /* 110f/120f */ u8 control2; -+ /* 1110/1210 */ u32 status; // write to clear -+ /* 1114/1214 */ u32 _unknown_1114; -+ /* 1118/1218 */ u64 _unknown_1118_guc_addr; -+ /* 1120/1220 */ u32 _unknown_1120_guc; -+ /* 1124/1224 */ u32 _unknown_1124_guc; -+ /* 1128/1228 */ u32 init_unknown; -+ /* 112c/122c */ u32 _unknown_112c; -+ /* 1130/1230 */ u64 _unknown_1130_guc_addr; -+ /* 1138/1238 */ u32 _unknown_1138_guc; -+ /* 113c/123c */ u32 _unknown_113c; -+ /* 1140/1240 */ u32 _unknown_1140_guc; -+ /* 1144/1244 */ u32 _unknown_1144[11]; -+ /* 1170/1270 */ u32 spi_addr; -+ /* 1174/1274 */ u32 _unknown_1174[11]; -+ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; -+ /* 11b8/12b8 */ u32 _unknown_11b8[18]; -+ } dma_rx[2]; -+}; -+static_assert(sizeof(struct ithc_registers) == 0x1300); -+ -+void bitsl(__iomem u32 *reg, u32 mask, u32 val); -+void bitsb(__iomem u8 *reg, u8 mask, u8 val); -+#define bitsl_set(reg, x) bitsl(reg, x, x) -+#define bitsb_set(reg, x) bitsb(reg, x, x) -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); -+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); -+ -+void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); -+void ithc_set_ltr_idle(struct ithc *ithc); -+int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); -+ -diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h -new file mode 100644 -index 000000000000..aec320d4e945 ---- /dev/null -+++ b/drivers/hid/ithc/ithc.h -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEVNAME "ithc" -+#define DEVFULLNAME "Intel Touch Host Controller" -+ -+#undef pr_fmt -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) -+#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) -+ -+#define NUM_RX_BUF 16 -+ -+// PCI device IDs: -+// Lakefield -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 -+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 -+// Tiger Lake -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 -+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 -+// Alder Lake -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 -+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 -+// Raptor Lake -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 -+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 -+// Meteor Lake -+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b -+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 -+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b -+ -+struct ithc; -+ -+#include "ithc-regs.h" -+#include "ithc-hid.h" -+#include "ithc-dma.h" -+#include "ithc-legacy.h" -+#include "ithc-quickspi.h" -+#include "ithc-debug.h" -+ -+struct ithc { -+ char phys[32]; -+ struct pci_dev *pci; -+ int irq; -+ struct task_struct *poll_thread; -+ struct timer_list idle_timer; -+ -+ struct ithc_registers __iomem *regs; -+ struct ithc_registers *prev_regs; // for debugging -+ struct ithc_dma_rx dma_rx[2]; -+ struct ithc_dma_tx dma_tx; -+ struct ithc_hid hid; -+ -+ bool use_quickspi; -+ bool have_config; -+ u16 vendor_id; -+ u16 product_id; -+ u32 product_rev; -+ u32 max_rx_size; -+ u32 max_tx_size; -+ u32 legacy_touch_cfg; -+}; -+ -+int ithc_reset(struct ithc *ithc); -+ --- -2.49.0 - diff --git a/patches/6.13-fedora/0007-surface-sam.patch b/patches/6.13-fedora/0007-surface-sam.patch deleted file mode 100644 index f990e2d047..0000000000 --- a/patches/6.13-fedora/0007-surface-sam.patch +++ /dev/null @@ -1,211 +0,0 @@ -From a0fe196b68e1a7fc549f760b547aee3ca1dea10c Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Fri, 17 Jun 2022 02:14:00 +0200 -Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator - Module - -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/rtc/Kconfig | 7 +++ - drivers/rtc/Makefile | 1 + - drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ - 3 files changed, 137 insertions(+) - create mode 100644 drivers/rtc/rtc-surface.c - -diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index a60bcc791a48..2de96e4c1ba6 100644 ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -1383,6 +1383,13 @@ config RTC_DRV_NTXEC - embedded controller found in certain e-book readers designed by the - original design manufacturer Netronix. - -+config RTC_DRV_SURFACE -+ tristate "Microsoft Surface Aggregator RTC" -+ depends on SURFACE_AGGREGATOR -+ depends on SURFACE_AGGREGATOR_BUS -+ help -+ TODO -+ - comment "on-CPU RTC drivers" - - config RTC_DRV_ASM9260 -diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile -index 489b4ab07068..061afa9db5b6 100644 ---- a/drivers/rtc/Makefile -+++ b/drivers/rtc/Makefile -@@ -180,6 +180,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o - obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o - obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o - obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o -+obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o - obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o - obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o - obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o -diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c -new file mode 100644 -index 000000000000..f6c17c4e98d5 ---- /dev/null -+++ b/drivers/rtc/rtc-surface.c -@@ -0,0 +1,129 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * AC driver for 7th-generation Microsoft Surface devices via Surface System -+ * Aggregator Module (SSAM). -+ * -+ * Copyright (C) 2019-2021 Maximilian Luz -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+struct surface_rtc { -+ struct ssam_device *sdev; -+ struct rtc_device *rtc; -+}; -+ -+SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { -+ .target_category = SSAM_SSH_TC_SAM, -+ .target_id = SSAM_SSH_TID_SAM, -+ .instance_id = 0x00, -+ .command_id = 0x10, -+}); -+ -+SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { -+ .target_category = SSAM_SSH_TC_SAM, -+ .target_id = SSAM_SSH_TID_SAM, -+ .instance_id = 0x00, -+ .command_id = 0x0f, -+}); -+ -+static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) -+{ -+ __le32 time_le; -+ int status; -+ -+ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); -+ if (status) -+ return status; -+ -+ *time = le32_to_cpu(time_le); -+ return 0; -+} -+ -+static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) -+{ -+ __le32 time_le = cpu_to_le32(time); -+ -+ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); -+} -+ -+static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) -+{ -+ struct surface_rtc *srtc = dev_get_drvdata(dev); -+ int status; -+ u32 time; -+ -+ status = ssam_rtc_get_unix_time(srtc, &time); -+ if (status) -+ return status; -+ -+ rtc_time64_to_tm(time, tm); -+ return 0; -+} -+ -+static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) -+{ -+ struct surface_rtc *srtc = dev_get_drvdata(dev); -+ time64_t time = rtc_tm_to_time64(tm); -+ -+ return ssam_rtc_set_unix_time(srtc, (u32)time); -+} -+ -+static const struct rtc_class_ops surface_rtc_ops = { -+ .read_time = surface_rtc_read_time, -+ .set_time = surface_rtc_set_time, -+}; -+ -+static int surface_rtc_probe(struct ssam_device *sdev) -+{ -+ struct surface_rtc *srtc; -+ -+ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); -+ if (!srtc) -+ return -ENOMEM; -+ -+ srtc->sdev = sdev; -+ -+ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); -+ if (IS_ERR(srtc->rtc)) -+ return PTR_ERR(srtc->rtc); -+ -+ srtc->rtc->ops = &surface_rtc_ops; -+ srtc->rtc->range_max = U32_MAX; -+ -+ ssam_device_set_drvdata(sdev, srtc); -+ -+ return devm_rtc_register_device(srtc->rtc); -+} -+ -+static void surface_rtc_remove(struct ssam_device *sdev) -+{ -+ /* Device-managed allocations take care of everything... */ -+} -+ -+static const struct ssam_device_id surface_rtc_match[] = { -+ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(ssam, surface_rtc_match); -+ -+static struct ssam_device_driver surface_rtc_driver = { -+ .probe = surface_rtc_probe, -+ .remove = surface_rtc_remove, -+ .match_table = surface_rtc_match, -+ .driver = { -+ .name = "surface_rtc", -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ }, -+}; -+module_ssam_device_driver(surface_rtc_driver); -+ -+MODULE_AUTHOR("Maximilian Luz "); -+MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); -+MODULE_LICENSE("GPL"); --- -2.49.0 - -From 92d3a8b58b89ed089e53517d1774f5670f7af4ab Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 20 Apr 2025 01:05:14 +0200 -Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 - (ACPI) - -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index a594d5fcfcfd..07b03aa4fa7f 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { - /* Surface Laptop 6 */ - { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, - -+ /* Surface Laptop 7 */ -+ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, -+ - /* Surface Laptop Go 1 */ - { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, - --- -2.49.0 - diff --git a/patches/6.13-fedora/0008-surface-sam-over-hid.patch b/patches/6.13-fedora/0008-surface-sam-over-hid.patch deleted file mode 100644 index 96dbee9a2a..0000000000 --- a/patches/6.13-fedora/0008-surface-sam-over-hid.patch +++ /dev/null @@ -1,308 +0,0 @@ -From f98ac023ab5b5b71124de89e18fe82bc425de93e Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 25 Jul 2020 17:19:53 +0200 -Subject: [PATCH] i2c: acpi: Implement RawBytes read access - -Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C -device via a generic serial bus operation region and RawBytes read -access. On the Surface Book 1, this access is required to turn on (and -off) the discrete GPU. - -Multiple things are to note here: - -a) The RawBytes access is device/driver dependent. The ACPI - specification states: - - > Raw accesses assume that the writer has knowledge of the bus that - > the access is made over and the device that is being accessed. The - > protocol may only ensure that the buffer is transmitted to the - > appropriate driver, but the driver must be able to interpret the - > buffer to communicate to a register. - - Thus this implementation may likely not work on other devices - accessing I2C via the RawBytes accessor type. - -b) The MSHW0030 I2C device is an HID-over-I2C device which seems to - serve multiple functions: - - 1. It is the main access point for the legacy-type Surface Aggregator - Module (also referred to as SAM-over-HID, as opposed to the newer - SAM-over-SSH/UART). It has currently not been determined on how - support for the legacy SAM should be implemented. Likely via a - custom HID driver. - - 2. It seems to serve as the HID device for the Integrated Sensor Hub. - This might complicate matters with regards to implementing a - SAM-over-HID driver required by legacy SAM. - -In light of this, the simplest approach has been chosen for now. -However, it may make more sense regarding breakage and compatibility to -either provide functionality for replacing or enhancing the default -operation region handler via some additional API functions, or even to -completely blacklist MSHW0030 from the I2C core and provide a custom -driver for it. - -Replacing/enhancing the default operation region handler would, however, -either require some sort of secondary driver and access point for it, -from which the new API functions would be called and the new handler -(part) would be installed, or hard-coding them via some sort of -quirk-like interface into the I2C core. - -Signed-off-by: Maximilian Luz -Patchset: surface-sam-over-hid ---- - drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index d2499f302b50..77ce5ec3dd9e 100644 ---- a/drivers/i2c/i2c-core-acpi.c -+++ b/drivers/i2c/i2c-core-acpi.c -@@ -661,6 +661,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, - return (ret == 1) ? 0 : -EIO; - } - -+static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, -+ u8 *data, u8 data_len) -+{ -+ struct i2c_msg msgs[1]; -+ int ret; -+ -+ msgs[0].addr = client->addr; -+ msgs[0].flags = client->flags; -+ msgs[0].len = data_len + 1; -+ msgs[0].buf = data; -+ -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret < 0) { -+ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* 1 transfer must have completed successfully */ -+ return (ret == 1) ? 0 : -EIO; -+} -+ - static acpi_status - i2c_acpi_space_handler(u32 function, acpi_physical_address command, - u32 bits, u64 *value64, -@@ -762,6 +783,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, - } - break; - -+ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: -+ if (action == ACPI_READ) { -+ dev_warn(&adapter->dev, -+ "protocol 0x%02x not supported for client 0x%02x\n", -+ accessor_type, client->addr); -+ ret = AE_BAD_PARAMETER; -+ goto err; -+ } else { -+ status = acpi_gsb_i2c_write_raw_bytes(client, -+ gsb->data, info->access_length); -+ } -+ break; -+ - default: - dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", - accessor_type, client->addr); --- -2.49.0 - -From 9bdc6328ce24cd5f739761d2b0c4db257e7378fb Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 13 Feb 2021 16:41:18 +0100 -Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch - -Add driver exposing the discrete GPU power-switch of the Microsoft -Surface Book 1 to user-space. - -On the Surface Book 1, the dGPU power is controlled via the Surface -System Aggregator Module (SAM). The specific SAM-over-HID command for -this is exposed via ACPI. This module provides a simple driver exposing -the ACPI call via a sysfs parameter to user-space, so that users can -easily power-on/-off the dGPU. - -Patchset: surface-sam-over-hid ---- - drivers/platform/surface/Kconfig | 7 + - drivers/platform/surface/Makefile | 1 + - .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ - 3 files changed, 144 insertions(+) - create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c - -diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index b629e82af97c..68656e8f309e 100644 ---- a/drivers/platform/surface/Kconfig -+++ b/drivers/platform/surface/Kconfig -@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH - Select M or Y here, if you want to provide tablet-mode switch input - events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. - -+config SURFACE_BOOK1_DGPU_SWITCH -+ tristate "Surface Book 1 dGPU Switch Driver" -+ depends on SYSFS -+ help -+ This driver provides a sysfs switch to set the power-state of the -+ discrete GPU found on the Microsoft Surface Book 1. -+ - config SURFACE_DTX - tristate "Surface DTX (Detachment System) Driver" - depends on SURFACE_AGGREGATOR -diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 ---- a/drivers/platform/surface/Makefile -+++ b/drivers/platform/surface/Makefile -@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o - obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o - obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o - obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o -+obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o - obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o - obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o - obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o -diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c -new file mode 100644 -index 000000000000..68db237734a1 ---- /dev/null -+++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c -@@ -0,0 +1,136 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include -+#include -+#include -+ -+/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ -+static const guid_t dgpu_sw_guid = -+ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, -+ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); -+ -+#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" -+#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" -+#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" -+ -+static int sb1_dgpu_sw_dsmcall(void) -+{ -+ union acpi_object *obj; -+ acpi_handle handle; -+ acpi_status status; -+ -+ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); -+ if (status) -+ return -EINVAL; -+ -+ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); -+ if (!obj) -+ return -EINVAL; -+ -+ ACPI_FREE(obj); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgon(struct device *dev) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); -+ if (status) { -+ dev_err(dev, "failed to run HGON: %d\n", status); -+ return -EINVAL; -+ } -+ -+ ACPI_FREE(buf.pointer); -+ -+ dev_info(dev, "turned-on dGPU via HGON\n"); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgof(struct device *dev) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); -+ if (status) { -+ dev_err(dev, "failed to run HGOF: %d\n", status); -+ return -EINVAL; -+ } -+ -+ ACPI_FREE(buf.pointer); -+ -+ dev_info(dev, "turned-off dGPU via HGOF\n"); -+ return 0; -+} -+ -+static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool value; -+ int status; -+ -+ status = kstrtobool(buf, &value); -+ if (status < 0) -+ return status; -+ -+ if (!value) -+ return 0; -+ -+ status = sb1_dgpu_sw_dsmcall(); -+ -+ return status < 0 ? status : len; -+} -+static DEVICE_ATTR_WO(dgpu_dsmcall); -+ -+static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool power; -+ int status; -+ -+ status = kstrtobool(buf, &power); -+ if (status < 0) -+ return status; -+ -+ if (power) -+ status = sb1_dgpu_sw_hgon(dev); -+ else -+ status = sb1_dgpu_sw_hgof(dev); -+ -+ return status < 0 ? status : len; -+} -+static DEVICE_ATTR_WO(dgpu_power); -+ -+static struct attribute *sb1_dgpu_sw_attrs[] = { -+ &dev_attr_dgpu_dsmcall.attr, -+ &dev_attr_dgpu_power.attr, -+ NULL -+}; -+ATTRIBUTE_GROUPS(sb1_dgpu_sw); -+ -+/* -+ * The dGPU power seems to be actually handled by MSHW0040. However, that is -+ * also the power-/volume-button device with a mainline driver. So let's use -+ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. -+ */ -+static const struct acpi_device_id sb1_dgpu_sw_match[] = { -+ { "MSHW0041", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); -+ -+static struct platform_driver sb1_dgpu_sw = { -+ .driver = { -+ .name = "surfacebook1_dgpu_switch", -+ .acpi_match_table = sb1_dgpu_sw_match, -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ .dev_groups = sb1_dgpu_sw_groups, -+ }, -+}; -+module_platform_driver(sb1_dgpu_sw); -+ -+MODULE_AUTHOR("Maximilian Luz "); -+MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); -+MODULE_LICENSE("GPL"); --- -2.49.0 - diff --git a/patches/6.13-fedora/0009-surface-button.patch b/patches/6.13-fedora/0009-surface-button.patch deleted file mode 100644 index e18120c2f1..0000000000 --- a/patches/6.13-fedora/0009-surface-button.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 5f9bc92e987765bd9439c5dd720dad422db3e5c9 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Tue, 5 Oct 2021 00:05:09 +1100 -Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices - -The power button on the AMD variant of the Surface Laptop uses the -same MSHW0040 device ID as the 5th and later generation of Surface -devices, however they report 0 for their OEM platform revision. As the -_DSM does not exist on the devices requiring special casing, check for -the existance of the _DSM to determine if soc_button_array should be -loaded. - -Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") -Co-developed-by: Maximilian Luz - -Signed-off-by: Sachi King -Patchset: surface-button ---- - drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- - 1 file changed, 8 insertions(+), 25 deletions(-) - -diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index b8cad415c62c..43b5d56383e3 100644 ---- a/drivers/input/misc/soc_button_array.c -+++ b/drivers/input/misc/soc_button_array.c -@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { - * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned - * devices use MSHW0040 for power and volume buttons, however the way they - * have to be addressed differs. Make sure that we only load this drivers -- * for the correct devices by checking the OEM Platform Revision provided by -- * the _DSM method. -+ * for the correct devices by checking if the OEM Platform Revision DSM call -+ * exists. - */ - #define MSHW0040_DSM_REVISION 0x01 - #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision -@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = - static int soc_device_check_MSHW0040(struct device *dev) - { - acpi_handle handle = ACPI_HANDLE(dev); -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, NULL, -- ACPI_TYPE_INTEGER); -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- /* -- * If the revision is zero here, the _DSM evaluation has failed. This -- * indicates that we have a Pro 4 or Book 1 and this driver should not -- * be used. -- */ -- if (oem_platform_rev == 0) -- return -ENODEV; -+ bool exists; - -- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); -+ // check if OEM platform revision DSM call exists -+ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - -- return 0; -+ return exists ? 0 : -ENODEV; - } - - /* --- -2.49.0 - -From 7ed80ee3276381056a25b279e75996aec50d9be0 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Tue, 5 Oct 2021 00:22:57 +1100 -Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd - variant - -The AMD variant of the Surface Laptop report 0 for their OEM platform -revision. The Surface devices that require the surfacepro3_button -driver do not have the _DSM that gets the OEM platform revision. If the -method does not exist, load surfacepro3_button. - -Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") -Co-developed-by: Maximilian Luz - -Signed-off-by: Sachi King -Patchset: surface-button ---- - drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- - 1 file changed, 6 insertions(+), 24 deletions(-) - -diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 ---- a/drivers/platform/surface/surfacepro3_button.c -+++ b/drivers/platform/surface/surfacepro3_button.c -@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) - /* - * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device - * ID (MSHW0040) for the power/volume buttons. Make sure this is the right -- * device by checking for the _DSM method and OEM Platform Revision. -+ * device by checking for the _DSM method and OEM Platform Revision DSM -+ * function. - * - * Returns true if the driver should bind to this device, i.e. the device is - * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. -@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) - static bool surface_button_check_MSHW0040(struct acpi_device *dev) - { - acpi_handle handle = dev->handle; -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, -- NULL, ACPI_TYPE_INTEGER); -- -- /* -- * If evaluating the _DSM fails, the method is not present. This means -- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we -- * should use this driver. We use revision 0 indicating it is -- * unavailable. -- */ -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); - -- return oem_platform_rev == 0; -+ // make sure that OEM platform revision DSM call does not exist -+ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - } - - --- -2.49.0 - diff --git a/patches/6.13-fedora/0010-surface-typecover.patch b/patches/6.13-fedora/0010-surface-typecover.patch deleted file mode 100644 index 4082f72ce8..0000000000 --- a/patches/6.13-fedora/0010-surface-typecover.patch +++ /dev/null @@ -1,575 +0,0 @@ -From 3199aa309ef61de73c2ec3497f749317b5f9a373 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sat, 18 Feb 2023 01:02:49 +0100 -Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 - Type-Cover - -The touchpad on the Type-Cover of the Surface Go 3 is sometimes not -being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this -issue. - -More specifically, the device in question is a fairly standard modern -touchpad with pointer and touchpad input modes. During setup, the device -needs to be switched from pointer- to touchpad-mode (which is done in -hid-multitouch) to fully utilize it as intended. Unfortunately, however, -this seems to occasionally fail silently, leaving the device in -pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. - -Link: https://github.com/linux-surface/linux-surface/issues/1059 -Signed-off-by: Maximilian Luz -Patchset: surface-typecover ---- - drivers/usb/core/quirks.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 6926bd639ec6..b08e3d206c31 100644 ---- a/drivers/usb/core/quirks.c -+++ b/drivers/usb/core/quirks.c -@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { - /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ - { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, - -+ /* Microsoft Surface Go 3 Type-Cover */ -+ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, -+ - /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ - { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, - --- -2.49.0 - -From 48079de103d77441dc589fc95393279dfd37befa Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= -Date: Thu, 5 Nov 2020 13:09:45 +0100 -Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when - suspending - -The Type Cover for Microsoft Surface devices supports a special usb -control request to disable or enable the built-in keyboard backlight. -On Windows, this request happens when putting the device into suspend or -resuming it, without it the backlight of the Type Cover will remain -enabled for some time even though the computer is suspended, which looks -weird to the user. - -So add support for this special usb control request to hid-multitouch, -which is the driver that's handling the Type Cover. - -The reason we have to use a pm_notifier for this instead of the usual -suspend/resume methods is that those won't get called in case the usb -device is already autosuspended. - -Also, if the device is autosuspended, we have to briefly autoresume it -in order to send the request. Doing that should be fine, the usb-core -driver does something similar during suspend inside choose_wakeup(). - -To make sure we don't send that request to every device but only to -devices which support it, add a new quirk -MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk -is only enabled for the usb id of the Surface Pro 2017 Type Cover, which -is where I confirmed that it's working. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- - 1 file changed, 98 insertions(+), 2 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e50887a6d22c..4ce18f21a141 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -35,7 +35,10 @@ - #include - #include - #include -+#include - #include -+#include -+#include - #include - #include - #include -@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); - MODULE_LICENSE("GPL"); - - #include "hid-ids.h" -+#include "usbhid/usbhid.h" - - /* quirks to control the device */ - #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) -@@ -73,12 +77,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 - - #define MT_BUTTONTYPE_CLICKPAD 0 - -+#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+ - enum latency_mode { - HID_LATENCY_NORMAL = 0, - HID_LATENCY_HIGH = 1, -@@ -176,6 +183,8 @@ struct mt_device { - - struct list_head applications; - struct list_head reports; -+ -+ struct notifier_block pm_notifier; - }; - - static void mt_post_parse_default_settings(struct mt_device *td, -@@ -220,6 +229,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_GOOGLE 0x0111 - #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 - #define MT_CLS_SMART_TECH 0x0113 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 - #define MT_CLS_SIS 0x0457 - - #define MT_DEFAULT_MAXCONTACT 10 -@@ -410,6 +420,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE, - }, -+ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, -+ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | -+ MT_QUIRK_ALWAYS_VALID | -+ MT_QUIRK_IGNORE_DUPLICATES | -+ MT_QUIRK_HOVERING | -+ MT_QUIRK_CONTACT_CNT_ACCURATE | -+ MT_QUIRK_STICKY_FINGERS | -+ MT_QUIRK_WIN8_PTP_BUTTONS, -+ .export_all_inputs = true -+ }, - { } - }; - -@@ -1759,6 +1779,69 @@ static void mt_expired_timeout(struct timer_list *t) - clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); - } - -+static void get_type_cover_backlight_field(struct hid_device *hdev, -+ struct hid_field **field) -+{ -+ struct hid_report_enum *rep_enum; -+ struct hid_report *rep; -+ struct hid_field *cur_field; -+ int i, j; -+ -+ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; -+ list_for_each_entry(rep, &rep_enum->report_list, list) { -+ for (i = 0; i < rep->maxfield; i++) { -+ cur_field = rep->field[i]; -+ -+ for (j = 0; j < cur_field->maxusage; j++) { -+ if (cur_field->usage[j].hid -+ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { -+ *field = cur_field; -+ return; -+ } -+ } -+ } -+ } -+} -+ -+static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) -+{ -+ struct usb_device *udev = hid_to_usb_dev(hdev); -+ struct hid_field *field = NULL; -+ -+ /* Wake up the device in case it's already suspended */ -+ pm_runtime_get_sync(&udev->dev); -+ -+ get_type_cover_backlight_field(hdev, &field); -+ if (!field) { -+ hid_err(hdev, "couldn't find backlight field\n"); -+ goto out; -+ } -+ -+ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; -+ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); -+ -+out: -+ pm_runtime_put_sync(&udev->dev); -+} -+ -+static int mt_pm_notifier(struct notifier_block *notifier, -+ unsigned long pm_event, -+ void *unused) -+{ -+ struct mt_device *td = -+ container_of(notifier, struct mt_device, pm_notifier); -+ struct hid_device *hdev = td->hdev; -+ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { -+ if (pm_event == PM_SUSPEND_PREPARE) -+ update_keyboard_backlight(hdev, 0); -+ else if (pm_event == PM_POST_SUSPEND) -+ update_keyboard_backlight(hdev, 1); -+ } -+ -+ return NOTIFY_DONE; -+} -+ - static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - { - int ret, i; -@@ -1782,6 +1865,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; - hid_set_drvdata(hdev, td); - -+ td->pm_notifier.notifier_call = mt_pm_notifier; -+ register_pm_notifier(&td->pm_notifier); -+ - INIT_LIST_HEAD(&td->applications); - INIT_LIST_HEAD(&td->reports); - -@@ -1820,8 +1906,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - timer_setup(&td->release_timer, mt_expired_timeout, 0); - - ret = hid_parse(hdev); -- if (ret != 0) -+ if (ret != 0) { -+ unregister_pm_notifier(&td->pm_notifier); - return ret; -+ } - - if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) - mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1830,8 +1918,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) - hdev->quirks |= HID_QUIRK_NOGET; - - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); -- if (ret) -+ if (ret) { -+ unregister_pm_notifier(&td->pm_notifier); - return ret; -+ } - - ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); - if (ret) -@@ -1881,6 +1971,7 @@ static void mt_remove(struct hid_device *hdev) - { - struct mt_device *td = hid_get_drvdata(hdev); - -+ unregister_pm_notifier(&td->pm_notifier); - del_timer_sync(&td->release_timer); - - sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2304,6 +2395,11 @@ static const struct hid_device_id mt_devices[] = { - MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, - USB_DEVICE_ID_XIROKU_CSR2) }, - -+ /* Microsoft Surface type cover */ -+ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, -+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, -+ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, -+ - /* Google MT devices */ - { .driver_data = MT_CLS_GOOGLE, - HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, --- -2.49.0 - -From bfb737e0a469bc8031f2e6d6007837e569b6fa3f Mon Sep 17 00:00:00 2001 -From: PJungkamp -Date: Fri, 25 Feb 2022 12:04:25 +0100 -Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet - switch - -The Surface Pro Type Cover has several non standard HID usages in it's -hid report descriptor. -I noticed that, upon folding the typecover back, a vendor specific range -of 4 32 bit integer hid usages is transmitted. -Only the first byte of the message seems to convey reliable information -about the keyboard state. - -0x22 => Normal (keys enabled) -0x33 => Folded back (keys disabled) -0x53 => Rotated left/right side up (keys disabled) -0x13 => Cover closed (keys disabled) -0x43 => Folded back and Tablet upside down (keys disabled) -This list may not be exhaustive. - -The tablet mode switch will be disabled for a value of 0x22 and enabled -on any other value. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ - 1 file changed, 122 insertions(+), 26 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 4ce18f21a141..f5e4d52bd2eb 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -85,6 +86,8 @@ MODULE_LICENSE("GPL"); - #define MT_BUTTONTYPE_CLICKPAD 0 - - #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 -+#define MS_TYPE_COVER_APPLICATION 0xff050050 - - enum latency_mode { - HID_LATENCY_NORMAL = 0, -@@ -422,6 +425,7 @@ static const struct mt_class mt_classes[] = { - }, - { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, - .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | -+ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_IGNORE_DUPLICATES | - MT_QUIRK_HOVERING | -@@ -1403,6 +1407,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - field->application != HID_CP_CONSUMER_CONTROL && - field->application != HID_GD_WIRELESS_RADIO_CTLS && - field->application != HID_GD_SYSTEM_MULTIAXIS && -+ !(field->application == MS_TYPE_COVER_APPLICATION && -+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && - !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && - application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) - return -1; -@@ -1430,6 +1437,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - return 1; - } - -+ /* -+ * The Microsoft Surface Pro Typecover has a non-standard HID -+ * tablet mode switch on a vendor specific usage page with vendor -+ * specific usage. -+ */ -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ usage->type = EV_SW; -+ usage->code = SW_TABLET_MODE; -+ *max = SW_MAX; -+ *bit = hi->input->swbit; -+ return 1; -+ } -+ - if (rdata->is_mt_collection) - return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, - application); -@@ -1451,6 +1473,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, - { - struct mt_device *td = hid_get_drvdata(hdev); - struct mt_report_data *rdata; -+ struct input_dev *input; - - rdata = mt_find_report_data(td, field->report); - if (rdata && rdata->is_mt_collection) { -@@ -1458,6 +1481,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, - return -1; - } - -+ /* -+ * We own an input device which acts as a tablet mode switch for -+ * the Surface Pro Typecover. -+ */ -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ input = hi->input; -+ input_set_capability(input, EV_SW, SW_TABLET_MODE); -+ input_report_switch(input, SW_TABLET_MODE, 0); -+ return -1; -+ } -+ - /* let hid-core decide for the others */ - return 0; - } -@@ -1467,11 +1503,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, - { - struct mt_device *td = hid_get_drvdata(hid); - struct mt_report_data *rdata; -+ struct input_dev *input; - - rdata = mt_find_report_data(td, field->report); - if (rdata && rdata->is_mt_collection) - return mt_touch_event(hid, field, usage, value); - -+ if (field->application == MS_TYPE_COVER_APPLICATION && -+ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && -+ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { -+ input = field->hidinput->input; -+ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); -+ input_sync(input); -+ return 1; -+ } -+ - return 0; - } - -@@ -1646,6 +1692,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) - app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; - } - -+static int get_type_cover_field(struct hid_report_enum *rep_enum, -+ struct hid_field **field, int usage) -+{ -+ struct hid_report *rep; -+ struct hid_field *cur_field; -+ int i, j; -+ -+ list_for_each_entry(rep, &rep_enum->report_list, list) { -+ for (i = 0; i < rep->maxfield; i++) { -+ cur_field = rep->field[i]; -+ if (cur_field->application != MS_TYPE_COVER_APPLICATION) -+ continue; -+ for (j = 0; j < cur_field->maxusage; j++) { -+ if (cur_field->usage[j].hid == usage) { -+ *field = cur_field; -+ return true; -+ } -+ } -+ } -+ } -+ return false; -+} -+ -+static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) -+{ -+ struct hid_field *field; -+ -+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], -+ &field, -+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { -+ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); -+ } else { -+ hid_err(hdev, "couldn't find tablet mode field\n"); -+ } -+} -+ - static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) - { - struct mt_device *td = hid_get_drvdata(hdev); -@@ -1694,6 +1776,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); - break; -+ case MS_TYPE_COVER_APPLICATION: -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { -+ suffix = "Tablet Mode Switch"; -+ request_type_cover_tablet_mode_switch(hdev); -+ break; -+ } -+ fallthrough; - default: - suffix = "UNKNOWN"; - break; -@@ -1779,30 +1868,6 @@ static void mt_expired_timeout(struct timer_list *t) - clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); - } - --static void get_type_cover_backlight_field(struct hid_device *hdev, -- struct hid_field **field) --{ -- struct hid_report_enum *rep_enum; -- struct hid_report *rep; -- struct hid_field *cur_field; -- int i, j; -- -- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; -- list_for_each_entry(rep, &rep_enum->report_list, list) { -- for (i = 0; i < rep->maxfield; i++) { -- cur_field = rep->field[i]; -- -- for (j = 0; j < cur_field->maxusage; j++) { -- if (cur_field->usage[j].hid -- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { -- *field = cur_field; -- return; -- } -- } -- } -- } --} -- - static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) - { - struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1811,8 +1876,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) - /* Wake up the device in case it's already suspended */ - pm_runtime_get_sync(&udev->dev); - -- get_type_cover_backlight_field(hdev, &field); -- if (!field) { -+ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], -+ &field, -+ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { - hid_err(hdev, "couldn't find backlight field\n"); - goto out; - } -@@ -1949,13 +2015,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) - - static int mt_reset_resume(struct hid_device *hdev) - { -+ struct mt_device *td = hid_get_drvdata(hdev); -+ - mt_release_contacts(hdev); - mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); -+ -+ /* Request an update on the typecover folding state on resume -+ * after reset. -+ */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) -+ request_type_cover_tablet_mode_switch(hdev); -+ - return 0; - } - - static int mt_resume(struct hid_device *hdev) - { -+ struct mt_device *td = hid_get_drvdata(hdev); -+ - /* Some Elan legacy devices require SET_IDLE to be set on resume. - * It should be safe to send it to other devices too. - * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1964,12 +2041,31 @@ static int mt_resume(struct hid_device *hdev) - - mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); - -+ /* Request an update on the typecover folding state on resume. */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) -+ request_type_cover_tablet_mode_switch(hdev); -+ - return 0; - } - - static void mt_remove(struct hid_device *hdev) - { - struct mt_device *td = hid_get_drvdata(hdev); -+ struct hid_field *field; -+ struct input_dev *input; -+ -+ /* Reset tablet mode switch on disconnect. */ -+ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { -+ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], -+ &field, -+ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { -+ input = field->hidinput->input; -+ input_report_switch(input, SW_TABLET_MODE, 0); -+ input_sync(input); -+ } else { -+ hid_err(hdev, "couldn't find tablet mode field\n"); -+ } -+ } - - unregister_pm_notifier(&td->pm_notifier); - del_timer_sync(&td->release_timer); --- -2.49.0 - diff --git a/patches/6.13-fedora/0011-surface-shutdown.patch b/patches/6.13-fedora/0011-surface-shutdown.patch deleted file mode 100644 index eb64d474a9..0000000000 --- a/patches/6.13-fedora/0011-surface-shutdown.patch +++ /dev/null @@ -1,97 +0,0 @@ -From ae923cbf9f936baf98fd05461fae2f184ab2eafa Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod - -Work around buggy EFI firmware: On some Microsoft Surface devices -(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with -EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the -system down, it returns and the system stays on. - -It turns out that this only happens after PCI shutdown callbacks ran for -specific devices. Excluding those devices from the shutdown process -makes the ResetSystem call work as expected. - -TODO: Maybe we can find a better way or the root cause of this? - -Not-Signed-off-by: Maximilian Luz -Patchset: surface-shutdown ---- - drivers/pci/pci-driver.c | 3 +++ - drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ - include/linux/pci.h | 1 + - 3 files changed, 40 insertions(+) - -diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 35270172c833..529779994ef6 100644 ---- a/drivers/pci/pci-driver.c -+++ b/drivers/pci/pci-driver.c -@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) - struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = pci_dev->driver; - -+ if (pci_dev->no_shutdown) -+ return; -+ - pm_runtime_resume(dev); - - if (drv && drv->shutdown) -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 8aba731f9ce3..5e02a01fefc2 100644 ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -6338,3 +6338,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); - #endif -+ -+static const struct dmi_system_id no_shutdown_dmi_table[] = { -+ /* -+ * Systems on which some devices should not be touched during shutdown. -+ */ -+ { -+ .ident = "Microsoft Surface Pro 9", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), -+ }, -+ }, -+ { -+ .ident = "Microsoft Surface Laptop 5", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), -+ }, -+ }, -+ {} -+}; -+ -+static void quirk_no_shutdown(struct pci_dev *dev) -+{ -+ if (!dmi_check_system(no_shutdown_dmi_table)) -+ return; -+ -+ dev->no_shutdown = 1; -+ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", -+ dev->vendor, dev->device); -+} -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU -diff --git a/include/linux/pci.h b/include/linux/pci.h -index f05903dd7695..d1e38fdaf8bb 100644 ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -476,6 +476,7 @@ struct pci_dev { - unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ - unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ - unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ -+ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; /* pci_enable_device has been called */ - --- -2.49.0 - diff --git a/patches/6.13-fedora/0012-surface-gpe.patch b/patches/6.13-fedora/0012-surface-gpe.patch deleted file mode 100644 index cf2ce019ca..0000000000 --- a/patches/6.13-fedora/0012-surface-gpe.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0660fd9f54beae759023eba1206bc335a0520456 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Sun, 12 Mar 2023 01:41:57 +0100 -Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 - -Add the lid GPE used by the Surface Pro 9. - -Signed-off-by: Maximilian Luz -Patchset: surface-gpe ---- - drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index b359413903b1..b4496db79f39 100644 ---- a/drivers/platform/surface/surface_gpe.c -+++ b/drivers/platform/surface/surface_gpe.c -@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { - {}, - }; - -+static const struct property_entry lid_device_props_l52[] = { -+ PROPERTY_ENTRY_U32("gpe", 0x52), -+ {}, -+}; -+ - static const struct property_entry lid_device_props_l57[] = { - PROPERTY_ENTRY_U32("gpe", 0x57), - {}, -@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { - }, - .driver_data = (void *)lid_device_props_l4B, - }, -+ { -+ /* -+ * We match for SKU here due to product name clash with the ARM -+ * version. -+ */ -+ .ident = "Surface Pro 9", -+ .matches = { -+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), -+ }, -+ .driver_data = (void *)lid_device_props_l52, -+ }, - { - .ident = "Surface Book 1", - .matches = { --- -2.49.0 - diff --git a/patches/6.13-fedora/0013-cameras.patch b/patches/6.13-fedora/0013-cameras.patch deleted file mode 100644 index c06d05b3ad..0000000000 --- a/patches/6.13-fedora/0013-cameras.patch +++ /dev/null @@ -1,734 +0,0 @@ -From c3ad75a88591c4fae17287d81ad262915b995a63 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sun, 10 Oct 2021 20:56:57 +0200 -Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an - INT3472 device - -The clk and regulator frameworks expect clk/regulator consumer-devices -to have info about the consumed clks/regulators described in the device's -fw_node. - -To work around cases where this info is not present in the firmware tables, -which is often the case on x86/ACPI devices, both frameworks allow the -provider-driver to attach info about consumers to the clks/regulators -when registering these. - -This causes problems with the probe ordering wrt drivers for consumers -of these clks/regulators. Since the lookups are only registered when the -provider-driver binds, trying to get these clks/regulators before then -results in a -ENOENT error for clks and a dummy regulator for regulators. - -One case where we hit this issue is camera sensors such as e.g. the OV8865 -sensor found on the Microsoft Surface Go. The sensor uses clks, regulators -and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 -ACPI device. There is special platform code handling this and setting -platform_data with the necessary consumer info on the MFD cells -instantiated for the PMIC under: drivers/platform/x86/intel/int3472. - -For this to work properly the ov8865 driver must not bind to the I2C-client -for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and -clk MFD cells have all been fully setup. - -The OV8865 on the Microsoft Surface Go is just one example, all X86 -devices using the Intel IPU3 camera block found on recent Intel SoCs -have similar issues where there is an INT3472 HID ACPI-device, which -describes the clks and regulators, and the driver for this INT3472 device -must be fully initialized before the sensor driver (any sensor driver) -binds for things to work properly. - -On these devices the ACPI nodes describing the sensors all have a _DEP -dependency on the matching INT3472 ACPI device (there is one per sensor). - -This allows solving the probe-ordering problem by delaying the enumeration -(instantiation of the I2C-client in the ov8865 example) of ACPI-devices -which have a _DEP dependency on an INT3472 device. - -The new acpi_dev_ready_for_enumeration() helper used for this is also -exported because for devices, which have the enumeration_by_parent flag -set, the parent-driver will do its own scan of child ACPI devices and -it will try to enumerate those during its probe(). Code doing this such -as e.g. the i2c-core-acpi.c code must call this new helper to ensure -that it too delays the enumeration until all the _DEP dependencies are -met on devices which have the new honor_deps flag set. - -Signed-off-by: Hans de Goede -Patchset: cameras ---- - drivers/acpi/scan.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index d6265ddc87ef..2a5fcdff4d69 100644 ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -2214,6 +2214,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, - - static void acpi_default_enumeration(struct acpi_device *device) - { -+ if (!acpi_dev_ready_for_enumeration(device)) -+ return; -+ - /* - * Do not enumerate devices with enumeration_by_parent flag set as - * they will be enumerated by their respective parents. --- -2.49.0 - -From 6cb288a1c01f510952bc52b2bfdfdc995f87df5a Mon Sep 17 00:00:00 2001 -From: zouxiaoh -Date: Fri, 25 Jun 2021 08:52:59 +0800 -Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs - -Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, -The IPU driver allocates its own page table that is not mapped -via the DMA, and thus the Intel IOMMU driver blocks access giving -this error: DMAR: DRHD: handling fault status reg 3 DMAR: -[DMA Read] Request device [00:05.0] PASID ffffffff -fault addr 76406000 [fault reason 06] PTE Read access is not set -As IPU is not an external facing device which is not risky, so use -IOMMU passthrough mode for Intel IPUs. - -Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b -Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 -Tracked-On: #JIITL8-411 -Signed-off-by: Bingbu Cao -Signed-off-by: zouxiaoh -Signed-off-by: Xu Chongyang -Patchset: cameras ---- - drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 1839a831a89f..ebd7aa6b9038 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -45,6 +45,13 @@ - ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ - ) - -+#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ -+ ((pdev)->device == 0x9a19 || \ -+ (pdev)->device == 0x9a39 || \ -+ (pdev)->device == 0x4e19 || \ -+ (pdev)->device == 0x465d || \ -+ (pdev)->device == 0x1919)) -+ - #define IOAPIC_RANGE_START (0xfee00000) - #define IOAPIC_RANGE_END (0xfeefffff) - #define IOVA_START_ADDR (0x1000) -@@ -214,12 +221,14 @@ int intel_iommu_enabled = 0; - EXPORT_SYMBOL_GPL(intel_iommu_enabled); - - static int dmar_map_ipts = 1; -+static int dmar_map_ipu = 1; - static int intel_iommu_superpage = 1; - static int iommu_identity_mapping; - static int iommu_skip_te_disable; - static int disable_igfx_iommu; - - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPU 8 - #define IDENTMAP_IPTS 16 - - const struct iommu_ops intel_iommu_ops; -@@ -1911,6 +1920,9 @@ static int device_def_domain_type(struct device *dev) - if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) - return IOMMU_DOMAIN_IDENTITY; - -+ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; -+ - if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) - return IOMMU_DOMAIN_IDENTITY; - } -@@ -2211,6 +2223,9 @@ static int __init init_dmars(void) - iommu_set_root_entry(iommu); - } - -+ if (!dmar_map_ipu) -+ iommu_identity_mapping |= IDENTMAP_IPU; -+ - if (!dmar_map_ipts) - iommu_identity_mapping |= IDENTMAP_IPTS; - -@@ -4522,6 +4537,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - disable_igfx_iommu = 1; - } - -+static void quirk_iommu_ipu(struct pci_dev *dev) -+{ -+ if (!IS_INTEL_IPU(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; -+ -+ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); -+ dmar_map_ipu = 0; -+} -+ - static void quirk_iommu_ipts(struct pci_dev *dev) - { - if (!IS_IPTS(dev)) -@@ -4569,6 +4596,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); - -+/* disable IPU dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); -+ - /* disable IPTS dmar support */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); --- -2.49.0 - -From 6ed7b1d776a5093ef202df1644aaf749d4c59e30 Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Sun, 10 Oct 2021 20:57:02 +0200 -Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain - -The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic -can be forwarded to a device connected to the PMIC as though it were -connected directly to the system bus. Enable this mode when the chip -is initialised. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 81ac4c691963..f453c9043042 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) - return ret; - } - -+ /* Enable I2C daisy chain */ -+ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); -+ if (ret) { -+ dev_err(dev, "Failed to enable i2c daisy chain\n"); -+ return ret; -+ } -+ - dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); - - return 0; --- -2.49.0 - -From afb5099a5ee3e5687f4950170338997e09c22d6d Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Thu, 2 Mar 2023 12:59:39 +0000 -Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E - -ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The -driver for this sensor expects a single pin named "enable", but on -some Microsoft Surface platforms the sensor is assigned a single -GPIO who's type flag is INT3472_GPIO_TYPE_RESET. - -Remap the GPIO pin's function from "reset" to "enable". This is done -outside of the existing remap table since it is a more widespread -discrepancy than that method is designed for. Additionally swap the -polarity of the pin to match the driver's expectation. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index a80c981caa34..68d0f07dda0c 100644 ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -81,12 +81,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - const char *func, unsigned long gpio_flags) - { - int ret; -+ const struct acpi_device_id ov7251_ids[] = { -+ { "INT347E" }, -+ { } -+ }; - - if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { - dev_warn(int3472->dev, "Too many GPIOs mapped\n"); - return -EINVAL; - } - -+ /* -+ * In addition to the function remap table we need to bulk remap the -+ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that -+ * expects its only GPIO pin to be called "enable" (and to have the -+ * opposite polarity). -+ */ -+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { -+ func = "enable"; -+ gpio_flags ^= GPIO_ACTIVE_LOW; -+ } -+ - ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, func, gpio_flags); - if (ret) --- -2.49.0 - -From 9f64f577e063bc55f0792e86749fae2be3edeb7d Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Tue, 21 Mar 2023 13:45:26 +0000 -Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 - -Update the control ID for the gain control in the ov7251 driver to -V4L2_CID_ANALOGUE_GAIN. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/media/i2c/ov7251.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf..9c1292ca8552 100644 ---- a/drivers/media/i2c/ov7251.c -+++ b/drivers/media/i2c/ov7251.c -@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) - case V4L2_CID_EXPOSURE: - ret = ov7251_set_exposure(ov7251, ctrl->val); - break; -- case V4L2_CID_GAIN: -+ case V4L2_CID_ANALOGUE_GAIN: - ret = ov7251_set_gain(ov7251, ctrl->val); - break; - case V4L2_CID_TEST_PATTERN: -@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) - ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, - V4L2_CID_EXPOSURE, 1, 32, 1, 32); - ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, -- V4L2_CID_GAIN, 16, 1023, 1, 16); -+ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); - v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, - V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(ov7251_test_pattern_menu) - 1, --- -2.49.0 - -From d0da4f26a459eccb3dff3e85bf5d4d62b0610815 Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Wed, 22 Mar 2023 11:01:42 +0000 -Subject: [PATCH] media: v4l2-core: Acquire privacy led in - v4l2_async_register_subdev() - -The current call to v4l2_subdev_get_privacy_led() is contained in -v4l2_async_register_subdev_sensor(), but that function isn't used by -all the sensor drivers. Move the acquisition of the privacy led to -v4l2_async_register_subdev() instead. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/media/v4l2-core/v4l2-async.c | 4 ++++ - drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index ee884a8221fb..4f6bafd900ee 100644 ---- a/drivers/media/v4l2-core/v4l2-async.c -+++ b/drivers/media/v4l2-core/v4l2-async.c -@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) - - INIT_LIST_HEAD(&sd->asc_list); - -+ ret = v4l2_subdev_get_privacy_led(sd); -+ if (ret < 0) -+ return ret; -+ - /* - * No reference taken. The reference is held by the device (struct - * v4l2_subdev.dev), and async sub-device does not exist independently -diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index f19c8adf2c61..923ed1b5ab8b 100644 ---- a/drivers/media/v4l2-core/v4l2-fwnode.c -+++ b/drivers/media/v4l2-core/v4l2-fwnode.c -@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) - - v4l2_async_subdev_nf_init(notifier, sd); - -- ret = v4l2_subdev_get_privacy_led(sd); -- if (ret < 0) -- goto out_cleanup; -- - ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); - if (ret < 0) - goto out_cleanup; --- -2.49.0 - -From 435c11d00b0daa5b011dc401e38ab209f10bca75 Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:16 +0800 -Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED - -Add MFD cell for tps68470-led. - -Reviewed-by: Daniel Scally -Signed-off-by: Kate Hsuan -Reviewed-by: Hans de Goede -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index f453c9043042..b8ad6b413e8b 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -17,7 +17,7 @@ - #define DESIGNED_FOR_CHROMEOS 1 - #define DESIGNED_FOR_WINDOWS 2 - --#define TPS68470_WIN_MFD_CELL_COUNT 3 -+#define TPS68470_WIN_MFD_CELL_COUNT 4 - - static const struct mfd_cell tps68470_cros[] = { - { .name = "tps68470-gpio" }, -@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) - cells[1].name = "tps68470-regulator"; - cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; - cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); -- cells[2].name = "tps68470-gpio"; -+ cells[2].name = "tps68470-led"; -+ cells[3].name = "tps68470-gpio"; - - for (i = 0; i < board_data->n_gpiod_lookups; i++) - gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); --- -2.49.0 - -From 8f5b49efb0cdf75553a1491e3620955581d369c2 Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:17 +0800 -Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB - -Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB -(TPS68470_ILEDCTL_ENB), and current control mask for LEDB -(TPS68470_ILEDCTL_CTRLB) - -Reviewed-by: Daniel Scally -Reviewed-by: Hans de Goede -Signed-off-by: Kate Hsuan -Patchset: cameras ---- - include/linux/mfd/tps68470.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 ---- a/include/linux/mfd/tps68470.h -+++ b/include/linux/mfd/tps68470.h -@@ -34,6 +34,7 @@ - #define TPS68470_REG_SGPO 0x22 - #define TPS68470_REG_GPDI 0x26 - #define TPS68470_REG_GPDO 0x27 -+#define TPS68470_REG_ILEDCTL 0x28 - #define TPS68470_REG_VCMVAL 0x3C - #define TPS68470_REG_VAUX1VAL 0x3D - #define TPS68470_REG_VAUX2VAL 0x3E -@@ -94,4 +95,8 @@ - #define TPS68470_GPIO_MODE_OUT_CMOS 2 - #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 - -+#define TPS68470_ILEDCTL_ENA BIT(2) -+#define TPS68470_ILEDCTL_ENB BIT(6) -+#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) -+ - #endif /* __LINUX_MFD_TPS68470_H */ --- -2.49.0 - -From 7ade024275c62ea257aa474632534b709d67fafa Mon Sep 17 00:00:00 2001 -From: Kate Hsuan -Date: Tue, 21 Mar 2023 23:37:18 +0800 -Subject: [PATCH] leds: tps68470: Add LED control for tps68470 - -There are two LED controllers, LEDA indicator LED and LEDB flash LED for -tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, -tps68470 provides four levels of power status for LEDB. If the -properties called "ti,ledb-current" can be found, the current will be -set according to the property values. These two LEDs can be controlled -through the LED class of sysfs (tps68470-leda and tps68470-ledb). - -Signed-off-by: Kate Hsuan -Reviewed-by: Hans de Goede -Patchset: cameras ---- - drivers/leds/Kconfig | 12 +++ - drivers/leds/Makefile | 1 + - drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ - 3 files changed, 198 insertions(+) - create mode 100644 drivers/leds/leds-tps68470.c - -diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index b784bb74a837..f8d8fcfacac2 100644 ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -941,6 +941,18 @@ config LEDS_TPS6105X - It is a single boost converter primarily for white LEDs and - audio amplifiers. - -+config LEDS_TPS68470 -+ tristate "LED support for TI TPS68470" -+ depends on LEDS_CLASS -+ depends on INTEL_SKL_INT3472 -+ help -+ This driver supports TPS68470 PMIC with LED chip. -+ It provides two LED controllers, with the ability to drive 2 -+ indicator LEDs and 2 flash LEDs. -+ -+ To compile this driver as a module, choose M and it will be -+ called leds-tps68470 -+ - config LEDS_IP30 - tristate "LED support for SGI Octane machines" - depends on LEDS_CLASS -diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 18afbb5a23ee..a1d16c0af82d 100644 ---- a/drivers/leds/Makefile -+++ b/drivers/leds/Makefile -@@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o - obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o - obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o - obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o -+obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o - obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o - obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o - obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o -diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c -new file mode 100644 -index 000000000000..35aeb5db89c8 ---- /dev/null -+++ b/drivers/leds/leds-tps68470.c -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * LED driver for TPS68470 PMIC -+ * -+ * Copyright (C) 2023 Red Hat -+ * -+ * Authors: -+ * Kate Hsuan -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define lcdev_to_led(led_cdev) \ -+ container_of(led_cdev, struct tps68470_led, lcdev) -+ -+#define led_to_tps68470(led, index) \ -+ container_of(led, struct tps68470_device, leds[index]) -+ -+enum tps68470_led_ids { -+ TPS68470_ILED_A, -+ TPS68470_ILED_B, -+ TPS68470_NUM_LEDS -+}; -+ -+static const char *tps68470_led_names[] = { -+ [TPS68470_ILED_A] = "tps68470-iled_a", -+ [TPS68470_ILED_B] = "tps68470-iled_b", -+}; -+ -+struct tps68470_led { -+ unsigned int led_id; -+ struct led_classdev lcdev; -+}; -+ -+struct tps68470_device { -+ struct device *dev; -+ struct regmap *regmap; -+ struct tps68470_led leds[TPS68470_NUM_LEDS]; -+}; -+ -+enum ctrlb_current { -+ CTRLB_2MA = 0, -+ CTRLB_4MA = 1, -+ CTRLB_8MA = 2, -+ CTRLB_16MA = 3, -+}; -+ -+static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) -+{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, -+ brightness ? TPS68470_ILEDCTL_ENA : 0); -+ case TPS68470_ILED_B: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, -+ brightness ? TPS68470_ILEDCTL_ENB : 0); -+ } -+ return -EINVAL; -+} -+ -+static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) -+{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ int ret = 0; -+ int value = 0; -+ -+ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); -+ if (ret) -+ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); -+ -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ value = value & TPS68470_ILEDCTL_ENA; -+ break; -+ case TPS68470_ILED_B: -+ value = value & TPS68470_ILEDCTL_ENB; -+ break; -+ } -+ -+ return value ? LED_ON : LED_OFF; -+} -+ -+ -+static int tps68470_ledb_current_init(struct platform_device *pdev, -+ struct tps68470_device *tps68470) -+{ -+ int ret = 0; -+ unsigned int curr; -+ -+ /* configure LEDB current if the properties can be got */ -+ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { -+ if (curr > CTRLB_16MA) { -+ dev_err(&pdev->dev, -+ "Invalid LEDB current value: %d\n", -+ curr); -+ return -EINVAL; -+ } -+ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, -+ TPS68470_ILEDCTL_CTRLB, curr); -+ } -+ return ret; -+} -+ -+static int tps68470_leds_probe(struct platform_device *pdev) -+{ -+ int i = 0; -+ int ret = 0; -+ struct tps68470_device *tps68470; -+ struct tps68470_led *led; -+ struct led_classdev *lcdev; -+ -+ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), -+ GFP_KERNEL); -+ if (!tps68470) -+ return -ENOMEM; -+ -+ tps68470->dev = &pdev->dev; -+ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); -+ -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ led = &tps68470->leds[i]; -+ lcdev = &led->lcdev; -+ -+ led->led_id = i; -+ -+ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", -+ tps68470_led_names[i], LED_FUNCTION_INDICATOR); -+ if (!lcdev->name) -+ return -ENOMEM; -+ -+ lcdev->max_brightness = 1; -+ lcdev->brightness = 0; -+ lcdev->brightness_set_blocking = tps68470_brightness_set; -+ lcdev->brightness_get = tps68470_brightness_get; -+ lcdev->dev = &pdev->dev; -+ -+ ret = devm_led_classdev_register(tps68470->dev, lcdev); -+ if (ret) { -+ dev_err_probe(tps68470->dev, ret, -+ "error registering led\n"); -+ goto err_exit; -+ } -+ -+ if (i == TPS68470_ILED_B) { -+ ret = tps68470_ledb_current_init(pdev, tps68470); -+ if (ret) -+ goto err_exit; -+ } -+ } -+ -+err_exit: -+ if (ret) { -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ if (tps68470->leds[i].lcdev.name) -+ devm_led_classdev_unregister(&pdev->dev, -+ &tps68470->leds[i].lcdev); -+ } -+ } -+ -+ return ret; -+} -+static struct platform_driver tps68470_led_driver = { -+ .driver = { -+ .name = "tps68470-led", -+ }, -+ .probe = tps68470_leds_probe, -+}; -+ -+module_platform_driver(tps68470_led_driver); -+ -+MODULE_ALIAS("platform:tps68470-led"); -+MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); -+MODULE_LICENSE("GPL v2"); --- -2.49.0 - -From a912466b23ce74196341f724384b46957d3a78b2 Mon Sep 17 00:00:00 2001 -From: mojyack -Date: Tue, 26 Mar 2024 05:55:44 +0900 -Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 - -On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". -The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. -So just add some delay. -There is no exact reason for this 10000us, but 100us failed. - -Patchset: cameras ---- - drivers/media/i2c/dw9719.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..0094cfda57ea 100644 ---- a/drivers/media/i2c/dw9719.c -+++ b/drivers/media/i2c/dw9719.c -@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) - if (ret) - return ret; - -+ /* Wait for device to be acknowledged */ -+ fsleep(10000); -+ - /* Jiggle SCL pin to wake up device */ - cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); - --- -2.49.0 - diff --git a/patches/6.13-fedora/0014-amd-gpio.patch b/patches/6.13-fedora/0014-amd-gpio.patch deleted file mode 100644 index caadf0232f..0000000000 --- a/patches/6.13-fedora/0014-amd-gpio.patch +++ /dev/null @@ -1,109 +0,0 @@ -From f8321346a2cfef4e6fe50b643a81798a96cc8bf6 Mon Sep 17 00:00:00 2001 -From: Sachi King -Date: Sat, 29 May 2021 17:47:38 +1000 -Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 - override - -This patch is the work of Thomas Gleixner and is -copied from: -https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ - -This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin -setup that is missing in the laptops ACPI table. - -This patch was used for validation of the issue, and is not a proper -fix, but is probably a better temporary hack than continuing to probe -the Legacy PIC and run with the PIC in an unknown state. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 18485170d51b..66d1b9e8aa9d 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -1172,6 +1173,17 @@ static void __init mp_config_acpi_legacy_irqs(void) - } - } - -+static const struct dmi_system_id surface_quirk[] __initconst = { -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") -+ }, -+ }, -+ {} -+}; -+ - /* - * Parse IOAPIC related entries in MADT - * returns 0 on success, < 0 on error -@@ -1228,6 +1240,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) - acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, - acpi_gbl_FADT.sci_interrupt); - -+ if (dmi_check_system(surface_quirk)) { -+ pr_warn("Surface hack: Override irq 7\n"); -+ mp_override_legacy_irq(7, 3, 3, 7); -+ } -+ - /* Fill in identity legacy mappings where no override */ - mp_config_acpi_legacy_irqs(); - --- -2.49.0 - -From 932d58e876e827ce1d705056b0b13c16efdbf427 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Thu, 3 Jun 2021 14:04:26 +0200 -Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override - quirk - -The 13" version of the Surface Laptop 4 has the same problem as the 15" -version, but uses a different SKU. Add that SKU to the quirk as well. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 66d1b9e8aa9d..741e05190b41 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -1175,12 +1175,19 @@ static void __init mp_config_acpi_legacy_irqs(void) - - static const struct dmi_system_id surface_quirk[] __initconst = { - { -- .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") - }, - }, -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") -+ }, -+ }, - {} - }; - --- -2.49.0 - diff --git a/patches/6.13-fedora/0015-rtc.patch b/patches/6.13-fedora/0015-rtc.patch deleted file mode 100644 index ecbb751b8a..0000000000 --- a/patches/6.13-fedora/0015-rtc.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 9ae940ef2a162d1175e19fe58451e3681d3cdeeb Mon Sep 17 00:00:00 2001 -From: "Bart Groeneveld | GPX Solutions B.V" -Date: Mon, 5 Dec 2022 16:08:46 +0100 -Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms - -The specification [1] allows so-called HW-reduced platforms, -which do not implement everything, especially the wakeup related stuff. - -In that case, it is still usable as a RTC. This is helpful for [2] -and [3], which is about a device with no other working RTC, -but it does have an HW-reduced TAD, which can be used as a RTC instead. - -[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device -[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 -[3]: https://github.com/linux-surface/linux-surface/issues/415 - -Signed-off-by: Bart Groeneveld | GPX Solutions B.V. -Patchset: rtc ---- - drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ - 1 file changed, 24 insertions(+), 12 deletions(-) - -diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 825c2a8acea4..74612088ac5f 100644 ---- a/drivers/acpi/acpi_tad.c -+++ b/drivers/acpi/acpi_tad.c -@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RO(caps); - -+static struct attribute *acpi_tad_attrs[] = { -+ &dev_attr_caps.attr, -+ NULL, -+}; -+static const struct attribute_group acpi_tad_attr_group = { -+ .attrs = acpi_tad_attrs, -+}; -+ - static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) - { -@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RW(ac_status); - --static struct attribute *acpi_tad_attrs[] = { -- &dev_attr_caps.attr, -+static struct attribute *acpi_tad_ac_attrs[] = { - &dev_attr_ac_alarm.attr, - &dev_attr_ac_policy.attr, - &dev_attr_ac_status.attr, - NULL, - }; --static const struct attribute_group acpi_tad_attr_group = { -- .attrs = acpi_tad_attrs, -+static const struct attribute_group acpi_tad_ac_attr_group = { -+ .attrs = acpi_tad_ac_attrs, - }; - - static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, -@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) - - pm_runtime_get_sync(dev); - -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) -+ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ - if (dd->capabilities & ACPI_TAD_DC_WAKE) - sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); - - sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); - -- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) { -+ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -+ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ } - if (dd->capabilities & ACPI_TAD_DC_WAKE) { - acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); - acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); -@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) - goto remove_handler; - } - -- if (!acpi_has_method(handle, "_PRW")) { -- dev_info(dev, "Missing _PRW\n"); -- ret = -ENODEV; -- goto remove_handler; -- } -- - dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); - if (!dd) { - ret = -ENOMEM; -@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) - if (ret) - goto fail; - -+ if (caps & ACPI_TAD_AC_WAKE) { -+ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ if (ret) -+ goto fail; -+ } -+ - if (caps & ACPI_TAD_DC_WAKE) { - ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); - if (ret) --- -2.49.0 - From eaed88d4a8e286c1525699379a5abd66742a6f8f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 21 Jun 2025 23:15:25 +0200 Subject: [PATCH 106/236] Add config for v6.15 Based on the current v6.14 config --- configs/surface-6.15.config | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 configs/surface-6.15.config diff --git a/configs/surface-6.15.config b/configs/surface-6.15.config new file mode 100644 index 0000000000..d58d539727 --- /dev/null +++ b/configs/surface-6.15.config @@ -0,0 +1,83 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +CONFIG_RTC_DRV_SURFACE=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m From 26b04e31e452a48e9682e22b81215a73c962b8e9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Jun 2025 02:29:32 +0200 Subject: [PATCH 107/236] Update v6.15 patches Changes: - Update ITHC from quo/ithc-linux - Rebase onto v6.15.3 Links: - kernel: https://github.com/linux-surface/kernel/commit/4efd7541364fab4008d8bc1ec669156e2b638094 --- patches/6.15/0001-secureboot.patch | 22 +- patches/6.15/0002-surface3.patch | 10 +- patches/6.15/0003-mwifiex.patch | 22 +- patches/6.15/0004-ath10k.patch | 6 +- patches/6.15/0005-ipts.patch | 34 +- patches/6.15/0006-ithc.patch | 53 +-- patches/6.15/0007-surface-sam.patch | 16 +- patches/6.15/0008-surface-sam-over-hid.patch | 8 +- patches/6.15/0009-surface-button.patch | 8 +- patches/6.15/0010-surface-typecover.patch | 350 ++++++++++++++++++- patches/6.15/0011-surface-shutdown.patch | 16 +- patches/6.15/0012-surface-gpe.patch | 4 +- patches/6.15/0013-cameras.patch | 133 ++----- patches/6.15/0014-amd-gpio.patch | 21 +- patches/6.15/0015-rtc.patch | 4 +- 15 files changed, 495 insertions(+), 212 deletions(-) diff --git a/patches/6.15/0001-secureboot.patch b/patches/6.15/0001-secureboot.patch index a850f2286e..3a8196b424 100644 --- a/patches/6.15/0001-secureboot.patch +++ b/patches/6.15/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 021ec07abb3238472d89815c934fb3dc07f1b29e Mon Sep 17 00:00:00 2001 +From 58aa22bec32223a605375d0aea0a961105ee3e50 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.49.0 +2.50.0 -From 4c1408f0a6a9ee5b1998253f4f30c04eb1e96240 Mon Sep 17 00:00:00 2001 +From ce1b44f9e408c1bc34413c8a4558df3770700340 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,10 +53,10 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index fb8752b42ec8..d46bb052b3a1 100644 +index 8f75ec177399..b6c4edfc3c13 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3154,6 +3154,11 @@ +@@ -3200,6 +3200,11 @@ to extract confidential information from the kernel are also disabled. @@ -69,10 +69,10 @@ index fb8752b42ec8..d46bb052b3a1 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 10a01af63a80..e53e4a86e4cc 100644 +index 5af9c7ee98cd..d52aa94e2fa2 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c -@@ -37,6 +37,7 @@ +@@ -38,6 +38,7 @@ #include "power.h" @@ -80,7 +80,7 @@ index 10a01af63a80..e53e4a86e4cc 100644 static int nocompress; static int noresume; static int nohibernate; -@@ -92,7 +93,7 @@ void hibernate_release(void) +@@ -98,7 +99,7 @@ bool hibernation_in_progress(void) bool hibernation_available(void) { return nohibernate == 0 && @@ -89,7 +89,7 @@ index 10a01af63a80..e53e4a86e4cc 100644 !secretmem_active() && !cxl_mem_active(); } -@@ -1434,6 +1435,12 @@ static int __init nohibernate_setup(char *str) +@@ -1440,6 +1441,12 @@ static int __init nohibernate_setup(char *str) return 1; } @@ -102,11 +102,11 @@ index 10a01af63a80..e53e4a86e4cc 100644 static const char * const comp_alg_enabled[] = { #if IS_ENABLED(CONFIG_CRYPTO_LZO) COMPRESSION_ALGO_LZO, -@@ -1492,3 +1499,4 @@ __setup("hibernate=", hibernate_setup); +@@ -1498,3 +1505,4 @@ __setup("hibernate=", hibernate_setup); __setup("resumewait", resumewait_setup); __setup("resumedelay=", resumedelay_setup); __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0002-surface3.patch b/patches/6.15/0002-surface3.patch index b45cfd8644..4350edbb97 100644 --- a/patches/6.15/0002-surface3.patch +++ b/patches/6.15/0002-surface3.patch @@ -1,4 +1,4 @@ -From 97e443f4ec202c66165990d72c05aa28c359b31e Mon Sep 17 00:00:00 2001 +From c16ae226b323ecaaf85b3313d572af82c1512f79 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -58,7 +58,7 @@ index 6c8fb7a4dde4..22797a53f4d8 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 51187b1e0ed2..bfb83ce8d8f8 100644 +index dba78efadc85..dbec816a2823 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -97,9 +97,9 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.49.0 +2.50.0 -From ebacd5e19eb63db32a538bab0d9e5b44737a24bb Mon Sep 17 00:00:00 2001 +From 6a1dfdbafe59e4c34fa9ea08995fe1fd81a953ff Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -230,5 +230,5 @@ index 6074b7730e86..6aa3e1d6f160 100644 } -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0003-mwifiex.patch b/patches/6.15/0003-mwifiex.patch index 3143915c46..3a7f1a75de 100644 --- a/patches/6.15/0003-mwifiex.patch +++ b/patches/6.15/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From fd57091b497bdd3467f99e6d79d3d7319b65938f Mon Sep 17 00:00:00 2001 +From 5edd27f4f92f91b33179da72382d94a7a6e4a724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -32,7 +32,7 @@ Patchset: mwifiex 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 5f997becdbaa..9a9929424513 100644 +index dd2a42e732f2..226640e7d486 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.49.0 +2.50.0 -From 9d16ab5d6b0253b5e5d28adab637ac0405052124 Mon Sep 17 00:00:00 2001 +From 32c223c4870502c93ea3a9546d1485cf06edb253 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -187,7 +187,7 @@ Patchset: mwifiex 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 9a9929424513..2273e3029776 100644 +index 226640e7d486..00abbb3997a8 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.49.0 +2.50.0 -From f44651e18ec650050bb04a1134209da6109a8232 Mon Sep 17 00:00:00 2001 +From 707482723cea399c4434e41d4d2b6745e7840bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 699ff21d9767..3568d5d4906e 100644 +index 256b451bbe06..ee7767cc1c9e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; @@ -367,7 +367,7 @@ index 699ff21d9767..3568d5d4906e 100644 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ -@@ -441,6 +442,7 @@ static const struct usb_device_id quirks_table[] = { +@@ -469,6 +470,7 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, @@ -375,7 +375,7 @@ index 699ff21d9767..3568d5d4906e 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3931,6 +3933,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3990,6 +3992,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 699ff21d9767..3568d5d4906e 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0004-ath10k.patch b/patches/6.15/0004-ath10k.patch index e50e6c5b27..de3891921c 100644 --- a/patches/6.15/0004-ath10k.patch +++ b/patches/6.15/0004-ath10k.patch @@ -1,4 +1,4 @@ -From bb582f0942d5b505c0c2744c5a24e1711ae9ce8f Mon Sep 17 00:00:00 2001 +From 4c65bd8db7df242e91af6990230b181df8cfa7a7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index b3294287bce1..2936fdae823c 100644 +index 6d336e39d673..d87366371688 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -40,6 +40,9 @@ static bool fw_diag_log; @@ -116,5 +116,5 @@ index b3294287bce1..2936fdae823c 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0005-ipts.patch b/patches/6.15/0005-ipts.patch index 7519047a5e..48688d6f5d 100644 --- a/patches/6.15/0005-ipts.patch +++ b/patches/6.15/0005-ipts.patch @@ -1,4 +1,4 @@ -From b89f20bfa13868323f9875acfe07e9d8f618329f Mon Sep 17 00:00:00 2001 +From c87b2ec3061da9f24432c8d6a1ffca4429f7aabd Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index a5f88ec97df7..e379dc2373b5 100644 +index bc40b940ae21..45fbd856d416 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index a5f88ec97df7..e379dc2373b5 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index d6ff9d82ae94..a1b714505f43 100644 +index 3f9c60b579ae..853a67753333 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index d6ff9d82ae94..a1b714505f43 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.49.0 +2.50.0 -From 8690c582cf49e817cff1f4ff216c4c1828682c78 Mon Sep 17 00:00:00 2001 +From 9a5cea04540ad007abd43f8176cc63a54767c9bd Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 25d31f8c129a..3735ed60032d 100644 +index cb0b993bebb4..c07d15343f76 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -91,7 +91,7 @@ index 25d31f8c129a..3735ed60032d 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -1902,6 +1909,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1935,6 +1942,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index 25d31f8c129a..3735ed60032d 100644 } return 0; -@@ -2196,6 +2206,9 @@ static int __init init_dmars(void) +@@ -2229,6 +2239,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index 25d31f8c129a..3735ed60032d 100644 check_tylersburg_isoch(); /* -@@ -4493,6 +4506,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4430,6 +4443,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index 25d31f8c129a..3735ed60032d 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4528,6 +4553,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4468,6 +4493,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index 25d31f8c129a..3735ed60032d 100644 { if (risky_device(dev)) -- -2.49.0 +2.50.0 -From 458d45bfbecaad616ed515d82abe8598fe8c2b0e Mon Sep 17 00:00:00 2001 +From c38605effe7f260704799b5c01e541098b3d9267 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,10 +211,10 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index dfc245867a46..f91ba8a06cfc 100644 +index 43859fc75747..ded8868dcfea 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1387,6 +1387,8 @@ source "drivers/hid/surface-hid/Kconfig" +@@ -1429,6 +1429,8 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/intel-thc-hid/Kconfig" @@ -224,10 +224,10 @@ index dfc245867a46..f91ba8a06cfc 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 0abfe51704a0..c86c9e80d225 100644 +index 10ae5dedbd84..7ba7d26391e9 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -172,3 +172,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ +@@ -175,3 +175,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ @@ -3239,5 +3239,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0006-ithc.patch b/patches/6.15/0006-ithc.patch index f3e96a5669..1624eb6e82 100644 --- a/patches/6.15/0006-ithc.patch +++ b/patches/6.15/0006-ithc.patch @@ -1,4 +1,4 @@ -From 85f3a4111005d23749f1a5b0424264ba38bbb3f4 Mon Sep 17 00:00:00 2001 +From effec31b7d5fc919c1e7c833ecaedfb646149d59 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,10 +10,10 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index ad795c772f21..2c10bca9e06b 100644 +index 3bc2a03cceca..e4c95c0a87f9 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c -@@ -388,6 +388,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) +@@ -380,6 +380,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) data.busmatch_count = 0; pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); @@ -37,9 +37,9 @@ index ad795c772f21..2c10bca9e06b 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.49.0 +2.50.0 -From 3e386a2ed36c9d620f4de23d671daa75a509d797 Mon Sep 17 00:00:00 2001 +From 6cb26a17c61fade693a12befdcbcb2b47770fc81 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -61,13 +61,13 @@ Patchset: ithc drivers/hid/ithc/ithc-hid.h | 32 ++ drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ drivers/hid/ithc/ithc-legacy.h | 8 + - drivers/hid/ithc/ithc-main.c | 431 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-main.c | 438 ++++++++++++++++++++++ drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ drivers/hid/ithc/ithc-quickspi.h | 39 ++ drivers/hid/ithc/ithc-regs.c | 154 ++++++++ drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ drivers/hid/ithc/ithc.h | 89 +++++ - 18 files changed, 2568 insertions(+) + 18 files changed, 2575 insertions(+) create mode 100644 drivers/hid/ithc/Kbuild create mode 100644 drivers/hid/ithc/Kconfig create mode 100644 drivers/hid/ithc/ithc-debug.c @@ -86,10 +86,10 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index f91ba8a06cfc..e945736e216f 100644 +index ded8868dcfea..d6bc87be4854 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1389,6 +1389,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" +@@ -1431,6 +1431,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" source "drivers/hid/ipts/Kconfig" @@ -99,10 +99,10 @@ index f91ba8a06cfc..e945736e216f 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index c86c9e80d225..046eb5fd8017 100644 +index 7ba7d26391e9..d939da7ac2e8 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -174,3 +174,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ +@@ -177,3 +177,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ obj-$(CONFIG_HID_IPTS) += ipts/ @@ -1203,10 +1203,10 @@ index 000000000000..28d692462072 + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000000..ac56c253674b +index 000000000000..094d878d671b --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c -@@ -0,0 +1,431 @@ +@@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause + +#include "ithc.h" @@ -1215,14 +1215,21 @@ index 000000000000..ac56c253674b +MODULE_LICENSE("Dual BSD/GPL"); + +static const struct pci_device_id ithc_pci_tbl[] = { -+ { -+ .vendor = PCI_VENDOR_ID_INTEL, -+ .device = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subdevice = PCI_ANY_ID, -+ .class = PCI_CLASS_INPUT_PEN << 8, -+ .class_mask = ~0, -+ }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) }, ++ // MTL and up are handled by drivers/hid/intel-thc-hid + {} +}; +MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); @@ -1446,7 +1453,7 @@ index 000000000000..ac56c253674b + else + ithc_legacy_exit(ithc); + ithc_disable(ithc); -+ del_timer_sync(&ithc->idle_timer); ++ timer_delete_sync(&ithc->idle_timer); + + // Clear DMA config. + for (unsigned int i = 0; i < 2; i++) { @@ -2769,5 +2776,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0007-surface-sam.patch b/patches/6.15/0007-surface-sam.patch index a4d7a23739..e580134f3c 100644 --- a/patches/6.15/0007-surface-sam.patch +++ b/patches/6.15/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 156b853c039f830407bea29f01bb6f3489c7c3e1 Mon Sep 17 00:00:00 2001 +From 0309bce8f2832eff001871abbe542a0fa2e08ba2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -14,10 +14,10 @@ Patchset: surface-sam create mode 100644 drivers/rtc/rtc-surface.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 0bbbf778ecfa..bd1d5c0dd6df 100644 +index 838bdc138ffe..0b7f712f23ea 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig -@@ -1383,6 +1383,13 @@ config RTC_DRV_NTXEC +@@ -1376,6 +1376,13 @@ config RTC_DRV_NTXEC embedded controller found in certain e-book readers designed by the original design manufacturer Netronix. @@ -32,10 +32,10 @@ index 0bbbf778ecfa..bd1d5c0dd6df 100644 config RTC_DRV_ASM9260 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile -index 489b4ab07068..061afa9db5b6 100644 +index 31473b3276d9..dba135e0a2a5 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile -@@ -180,6 +180,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o +@@ -179,6 +179,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o @@ -179,9 +179,9 @@ index 000000000000..f6c17c4e98d5 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.49.0 +2.50.0 -From 3dec366702ebcfb04f7805144eca4c943d19802b Mon Sep 17 00:00:00 2001 +From c48bf4e09c8b09686bf938428dbc48ad192965ea Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -207,5 +207,5 @@ index a594d5fcfcfd..07b03aa4fa7f 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0008-surface-sam-over-hid.patch b/patches/6.15/0008-surface-sam-over-hid.patch index 293932558f..4bf15cf71c 100644 --- a/patches/6.15/0008-surface-sam-over-hid.patch +++ b/patches/6.15/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From b0c24f19804345b57672cf54e5caa7ba473f3f26 Mon Sep 17 00:00:00 2001 +From c8d17a0b05fc10ed5025942fb7411b6991cfccfd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index d2499f302b50..77ce5ec3dd9e 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.49.0 +2.50.0 -From b27002518a3b386bc3c2d50d7e45c94148375aa4 Mon Sep 17 00:00:00 2001 +From 127b0fcb832e5606d77ca98daa7268b5f5bdf76b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0009-surface-button.patch b/patches/6.15/0009-surface-button.patch index c0676281f3..fef2769d5f 100644 --- a/patches/6.15/0009-surface-button.patch +++ b/patches/6.15/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 3e79d7b95f28bfcd981ca7db961407b2375307be Mon Sep 17 00:00:00 2001 +From 5f6aee8e72a7dbabba5c1cbbc6245a891cbc4ba3 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index b8cad415c62c..43b5d56383e3 100644 /* -- -2.49.0 +2.50.0 -From 8cbc63032afb8606805a14cc1c5f29d9105567c0 Mon Sep 17 00:00:00 2001 +From 21c595df17f9a0d2016cf0285ed78912711bac95 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0010-surface-typecover.patch b/patches/6.15/0010-surface-typecover.patch index f6cb483ced..152ff689e5 100644 --- a/patches/6.15/0010-surface-typecover.patch +++ b/patches/6.15/0010-surface-typecover.patch @@ -1,4 +1,45 @@ -From 76accddaf1b7b28acb671305efb2a71eee0ea4af Mon Sep 17 00:00:00 2001 +From 9e611153712541c8dde237599028c05ddfc8443d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 53d68d20fb62..cf85b30b1d60 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.50.0 + +From 875ba51655d8bf28f70a2e9e6831d7e454382d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -34,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e50887a6d22c..4ce18f21a141 100644 +index 7ac8e16e6158..41017a552681 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -210,7 +251,7 @@ index e50887a6d22c..4ce18f21a141 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1881,7 +1971,8 @@ static void mt_remove(struct hid_device *hdev) +@@ -1881,6 +1971,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -218,7 +259,6 @@ index e50887a6d22c..4ce18f21a141 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); - hid_hw_stop(hdev); @@ -2304,6 +2395,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -232,4 +272,304 @@ index e50887a6d22c..4ce18f21a141 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.49.0 \ No newline at end of file +2.50.0 + +From 4f5ba1c992de1e614aa8dea5412f4835da545a7e Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 41017a552681..e1ce20b3bb8f 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -85,6 +86,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -422,6 +425,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1403,6 +1407,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1430,6 +1437,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1451,6 +1473,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1458,6 +1481,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1467,11 +1503,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1646,6 +1692,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1694,6 +1776,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1779,30 +1868,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1811,8 +1876,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1949,13 +2015,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1964,12 +2041,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); +-- +2.50.0 + diff --git a/patches/6.15/0011-surface-shutdown.patch b/patches/6.15/0011-surface-shutdown.patch index 78f51d0046..34d4c0ccf3 100644 --- a/patches/6.15/0011-surface-shutdown.patch +++ b/patches/6.15/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 26f09bed8d9daf48f62882e9e0307f2c81130870 Mon Sep 17 00:00:00 2001 +From d3afc544e9d422f244aba40244a2293e96cba76b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index f57ea36d125d..cdb74ec6c082 100644 +index c8bd71a739f7..0656b4d3e0e5 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,7 +37,7 @@ index f57ea36d125d..cdb74ec6c082 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 82b21e34c545..ccf29cfa7082 100644 +index 94daca15a096..506d399cda42 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6316,3 +6316,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) @@ -81,17 +81,17 @@ index 82b21e34c545..ccf29cfa7082 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 47b31ad724fa..c571fdca6c5f 100644 +index 081e5c0a3ddf..e552c8bed5fe 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -476,6 +476,7 @@ struct pci_dev { - unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ +@@ -480,6 +480,7 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ -+ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ + -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0012-surface-gpe.patch b/patches/6.15/0012-surface-gpe.patch index 605d05eba6..98157ef94b 100644 --- a/patches/6.15/0012-surface-gpe.patch +++ b/patches/6.15/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 0ea6591811ba84ac67dc7bb320d2048e949f7aad Mon Sep 17 00:00:00 2001 +From d2e23db264d326900aebdea72da76f73184f1588 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index b359413903b1..b4496db79f39 100644 .ident = "Surface Book 1", .matches = { -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0013-cameras.patch b/patches/6.15/0013-cameras.patch index 796f9342c3..b1586f5f1a 100644 --- a/patches/6.15/0013-cameras.patch +++ b/patches/6.15/0013-cameras.patch @@ -1,4 +1,4 @@ -From 8678f0c1ed1a9d4f5cad1e0c0c677630a242d4bd Mon Sep 17 00:00:00 2001 +From 673bc3f1e5f697afc8066e59245458935f28546c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,10 +58,10 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 9f4efa8f75a6..7c7ef03cafa4 100644 +index fb1fe9f3b1a3..5be8893b3912 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c -@@ -2204,6 +2204,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, +@@ -2197,6 +2197,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, static void acpi_default_enumeration(struct acpi_device *device) { @@ -72,9 +72,9 @@ index 9f4efa8f75a6..7c7ef03cafa4 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.49.0 +2.50.0 -From 069b8c0dd7460410d2e4d333bc533221d709cb17 Mon Sep 17 00:00:00 2001 +From cf8447073f3dee50253c653d9b20ae9cc52a5106 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 3735ed60032d..71cccee6e4a9 100644 +index c07d15343f76..f0fd3155340a 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -132,7 +132,7 @@ index 3735ed60032d..71cccee6e4a9 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -1910,6 +1919,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1943,6 +1952,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index 3735ed60032d..71cccee6e4a9 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2206,6 +2218,9 @@ static int __init init_dmars(void) +@@ -2239,6 +2251,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index 3735ed60032d..71cccee6e4a9 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4506,6 +4521,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4443,6 +4458,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index 3735ed60032d..71cccee6e4a9 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4553,6 +4580,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4493,6 +4520,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index 3735ed60032d..71cccee6e4a9 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.49.0 +2.50.0 -From 5bc57f06d3dc085a2a0757fc5c35be36c2d6d341 Mon Sep 17 00:00:00 2001 +From d4df94633dd54daa123fb5497a741d5f0d8d9b9e Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,71 +219,9 @@ index 81ac4c691963..f453c9043042 100644 return 0; -- -2.49.0 +2.50.0 -From c7a4afe01bfd24fbfc3735d1b60f08be3aef0b81 Mon Sep 17 00:00:00 2001 -From: Daniel Scally -Date: Thu, 2 Mar 2023 12:59:39 +0000 -Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E - -ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The -driver for this sensor expects a single pin named "enable", but on -some Microsoft Surface platforms the sensor is assigned a single -GPIO who's type flag is INT3472_GPIO_TYPE_RESET. - -Remap the GPIO pin's function from "reset" to "enable". This is done -outside of the existing remap table since it is a more widespread -discrepancy than that method is designed for. Additionally swap the -polarity of the pin to match the driver's expectation. - -Signed-off-by: Daniel Scally -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 092252eb95a8..7a73d5f903a9 100644 ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -81,18 +81,33 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio, - const char *con_id, unsigned long gpio_flags) - { - int ret; -+ const struct acpi_device_id ov7251_ids[] = { -+ { "INT347E" }, -+ { } -+ }; - - if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { - dev_warn(int3472->dev, "Too many GPIOs mapped\n"); - return -EINVAL; - } - -+ /* -+ * In addition to the function remap table we need to bulk remap the -+ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that -+ * expects its only GPIO pin to be called "enable" (and to have the -+ * opposite polarity). -+ */ -+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { -+ func = "enable"; -+ gpio_flags ^= GPIO_ACTIVE_LOW; -+ } -+ - ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, con_id, gpio_flags); - if (ret) - return ret; - - int3472->n_sensor_gpios++; - - return 0; --- -2.49.0 - -From 9ab2f02228baf5661844d4ba55810273b75cb456 Mon Sep 17 00:00:00 2001 +From a0ce4892cc5518186d1fb1f54d61aaf7fd4ca64e Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -298,10 +236,10 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf..9c1292ca8552 100644 +index 3226888d77e9..3bfe45b764f7 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c -@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) +@@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE: ret = ov7251_set_exposure(ov7251, ctrl->val); break; @@ -310,7 +248,7 @@ index 30f61e04ecaf..9c1292ca8552 100644 ret = ov7251_set_gain(ov7251, ctrl->val); break; case V4L2_CID_TEST_PATTERN: -@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) +@@ -1574,7 +1574,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, V4L2_CID_EXPOSURE, 1, 32, 1, 32); ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, @@ -320,9 +258,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.49.0 +2.50.0 -From 4cfbc183671a5e27fb1808a0489dc4053ff970aa Mon Sep 17 00:00:00 2001 +From 75ac36f76af5da0031f58d842158d2a07fc2fe28 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -371,9 +309,9 @@ index cb153ce42c45..f11b499e14bb 100644 if (ret < 0) goto out_cleanup; -- -2.49.0 +2.50.0 -From 6bede17be7b28d507138775eda22c15c020ee22d Mon Sep 17 00:00:00 2001 +From a726339cb0b04a33e5cf091d7e400e46d3a0fe00 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -412,9 +350,9 @@ index f453c9043042..b8ad6b413e8b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.49.0 +2.50.0 -From 4b91d36e045045a2f5029a47b33984c33a1d58cf Mon Sep 17 00:00:00 2001 +From 15ebc12622ba3d93a9f554e927a63e9e8672f40b Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -453,9 +391,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.49.0 +2.50.0 -From 4606e818fd812630708c340acdc7a493d703842d Mon Sep 17 00:00:00 2001 +From 726379fff106ed4f53dd44877af3a23fd879145c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -478,10 +416,10 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 2b27d043921c..22a8c20de32a 100644 +index a104cbb0a001..535a10cbbff1 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig -@@ -985,6 +985,18 @@ config LEDS_TPS6105X +@@ -995,6 +995,18 @@ config LEDS_TPS6105X It is a single boost converter primarily for white LEDs and audio amplifiers. @@ -501,10 +439,10 @@ index 2b27d043921c..22a8c20de32a 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 6ad52e219ec6..3519b4c32c9e 100644 +index 2f170d69dcbf..17f0ecd1f52e 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile -@@ -91,6 +91,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o +@@ -92,6 +92,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o @@ -704,9 +642,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.49.0 +2.50.0 -From 2666871d2780d86053ac2d61350de05de6888204 Mon Sep 17 00:00:00 2001 +From 2e92d47015628f6ed7e3fbd68f2df381fb739876 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -722,10 +660,10 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..0094cfda57ea 100644 +index 032fbcb981f2..e03a1d8cdcb4 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c -@@ -82,9 +82,12 @@ static int dw9719_power_up(struct dw9719_device *dw9719) +@@ -87,6 +87,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) if (ret) return ret; @@ -735,9 +673,6 @@ index c626ed845928..0094cfda57ea 100644 /* Jiggle SCL pin to wake up device */ cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); fsleep(100); - cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_STANDBY, &ret); - /* Need 100us to transit from SHUTDOWN to STANDBY */ - fsleep(100); -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0014-amd-gpio.patch b/patches/6.15/0014-amd-gpio.patch index 10af4fc612..f0f6f2f55a 100644 --- a/patches/6.15/0014-amd-gpio.patch +++ b/patches/6.15/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From dc693e53aeaa7bcfea526f8867a3c2c3d027e7ef Mon Sep 17 00:00:00 2001 +From d259acfe5ae92dee7a87903b9ec114707d32a887 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,17 +21,18 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index dae6a73be40e..f401a6676b5e 100644 +index 9fa321a95eb3..8914a922be2b 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -22,5 +22,6 @@ +@@ -22,6 +22,7 @@ #include #include #include +#include #include -@@ -1169,6 +1170,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + +@@ -1171,6 +1172,17 @@ static void __init mp_config_acpi_legacy_irqs(void) } } @@ -49,7 +50,7 @@ index dae6a73be40e..f401a6676b5e 100644 /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -@@ -1225,6 +1237,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) +@@ -1227,6 +1239,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, acpi_gbl_FADT.sci_interrupt); @@ -62,9 +63,9 @@ index dae6a73be40e..f401a6676b5e 100644 mp_config_acpi_legacy_irqs(); -- -2.49.0 +2.50.0 -From 61a2673dc1feba27dea028f0e373081a19f3b6f6 Mon Sep 17 00:00:00 2001 +From 45731a8b193e36dfe5987a635bb69088dc9cc4b6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -79,10 +80,10 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index f401a6676b5e..fe3df37bfaff 100644 +index 8914a922be2b..c43d0a553867 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -1172,12 +1172,19 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) static const struct dmi_system_id surface_quirk[] __initconst = { { @@ -104,5 +105,5 @@ index f401a6676b5e..fe3df37bfaff 100644 }; -- -2.49.0 +2.50.0 diff --git a/patches/6.15/0015-rtc.patch b/patches/6.15/0015-rtc.patch index a46655ddf9..6948e9f154 100644 --- a/patches/6.15/0015-rtc.patch +++ b/patches/6.15/0015-rtc.patch @@ -1,4 +1,4 @@ -From 15bf9fcbacae64d8a208be07828b4aa7ae031482 Mon Sep 17 00:00:00 2001 +From 3f0e0d5ea7b1ac2508a86d1abbef5a346ee4fe4e Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 825c2a8acea4..74612088ac5f 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.49.0 +2.50.0 From 72988a8dfb928596f0f65b9751c7c55dbb41563f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Jun 2025 02:46:36 +0200 Subject: [PATCH 108/236] Update Fedora kernels to v6.14.11 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index d0c8854708..6dae8eceaf 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.14.2-0" +PACKAGE_TAG = "kernel-6.14.11-0" ## ## The release number of the modified kernel package. From 8955bb2658032af7437f2110e92ddefb9d0f744a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Jun 2025 02:50:28 +0200 Subject: [PATCH 109/236] Update Arch Linux kernel to v6.15.3 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- pkg/arch/kernel/0007-surface-sam.patch | 2 +- .../kernel/0008-surface-sam-over-hid.patch | 2 +- pkg/arch/kernel/0009-surface-button.patch | 2 +- pkg/arch/kernel/0010-surface-typecover.patch | 2 +- pkg/arch/kernel/0011-surface-shutdown.patch | 2 +- pkg/arch/kernel/0012-surface-gpe.patch | 2 +- pkg/arch/kernel/0013-cameras.patch | 2 +- pkg/arch/kernel/0014-amd-gpio.patch | 2 +- pkg/arch/kernel/0015-rtc.patch | 2 +- pkg/arch/kernel/PKGBUILD | 34 +++++++++---------- pkg/arch/kernel/surface.config | 2 +- 17 files changed, 33 insertions(+), 33 deletions(-) diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 96dd8af4bb..b7e342e784 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.14/0001-secureboot.patch \ No newline at end of file +../../../patches/6.15/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3.patch b/pkg/arch/kernel/0002-surface3.patch index ad70e0813d..4c1981bd89 120000 --- a/pkg/arch/kernel/0002-surface3.patch +++ b/pkg/arch/kernel/0002-surface3.patch @@ -1 +1 @@ -../../../patches/6.14/0002-surface3.patch \ No newline at end of file +../../../patches/6.15/0002-surface3.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index 8c498e0963..13d724e5ae 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.14/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.15/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index dd86ef8d3c..1c63455ed5 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.14/0004-ath10k.patch \ No newline at end of file +../../../patches/6.15/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index ae82eb0b50..897a46c64e 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.14/0005-ipts.patch \ No newline at end of file +../../../patches/6.15/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index fd7f0f2f30..01c5e06b81 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.14/0006-ithc.patch \ No newline at end of file +../../../patches/6.15/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch index a4db0ba73a..516a14dcb7 120000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -1 +1 @@ -../../../patches/6.14/0007-surface-sam.patch \ No newline at end of file +../../../patches/6.15/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch index 8d0eae142b..c4a1aa9b50 120000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -1 +1 @@ -../../../patches/6.14/0008-surface-sam-over-hid.patch \ No newline at end of file +../../../patches/6.15/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch index c504a293b4..5405d95fa7 120000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -1 +1 @@ -../../../patches/6.14/0009-surface-button.patch \ No newline at end of file +../../../patches/6.15/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch index fd9dc210b6..f59090d526 120000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -1 +1 @@ -../../../patches/6.14/0010-surface-typecover.patch \ No newline at end of file +../../../patches/6.15/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch index d47226f64f..e47d476e18 120000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -1 +1 @@ -../../../patches/6.14/0011-surface-shutdown.patch \ No newline at end of file +../../../patches/6.15/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch index 405637eede..43a06eef61 120000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -1 +1 @@ -../../../patches/6.14/0012-surface-gpe.patch \ No newline at end of file +../../../patches/6.15/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch index 222488ce24..7b7d8ee7c9 120000 --- a/pkg/arch/kernel/0013-cameras.patch +++ b/pkg/arch/kernel/0013-cameras.patch @@ -1 +1 @@ -../../../patches/6.14/0013-cameras.patch \ No newline at end of file +../../../patches/6.15/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch index 31f5bdc0cb..da4f80ad89 120000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -1 +1 @@ -../../../patches/6.14/0014-amd-gpio.patch \ No newline at end of file +../../../patches/6.15/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch index 84733bb558..57a4abf094 120000 --- a/pkg/arch/kernel/0015-rtc.patch +++ b/pkg/arch/kernel/0015-rtc.patch @@ -1 +1 @@ -../../../patches/6.14/0015-rtc.patch \ No newline at end of file +../../../patches/6.15/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 5ff90a9a0a..4d436f7920 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.14.2.arch1 +pkgver=6.15.3.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('8fb801ac0004d22dbfc498266b156f13148272737ae42514169e7a56d72fd673' +sha256sums=('13443654c25cebb5b3e462a02cdb9b5cd47fe3e45331f06440a9c0d9e9236e7b' 'a6a234cd982d21f0d7daa3ba921293e450abd87ff5d7474d4a153b3f34cfabc5' '8a68dbf5e7875f0d6a99c6aeb1dc913cc320fcb4e29c7fe388dc2ed7d81ac76b' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '77020395ec2fa3dcc609b9c984fec7f97fae196f0a24436031abbd4988b86300' - 'd73b19dc2b070272ffeffcbae862691ed03fb215e8f232b954fe9f6ed509e80c' - '718fd1b9cfbb0818235f78e440890f989dd969f784ff0e4aee52c36a078ca126' - 'cda4ef1533326aace8562d2a5fe4300f2fc3773ec11f7c2550ca4876e1139018' - 'a05467f5825e279e189b2ca926efe698077769b70428e8f61689d8e0f70c6c39' - '2d141c2dec6190d5bd51ecb82e79bdcbc0babe64b3299088d45a6a267acbb424' - '814be3c48392cdcf6b5df4575cb87e91839cc2b89750a3646c99357ab565cf1a' - '18f602335a757f81235c749650f403029fccc590317c61fd3d8842678e49b16d' - '7f42df95c3efb058f716776e21391a423083792063ed7693c3293f6556f74935' - '72be9823fd1bad0a039bb2e4b55997030f8e98b5144ed3c5c6f85d6995426cf9' - 'cae8e878df9c8590defe5e3bc01ce54ed0b98db9df1077fd9e5af175f308bbc5' - 'f19165e6c43a37d670f47f43505786ba0f788b06003918c2d0443c287cfb281a' - '21d9064e2d3be7b70bee5347d8dc748068ed1ad18f8f357a0e88fd73e16dbd77' - '92f88078a04a37706a1ed8ca04004c4318ddecb746804a2abd73f2342a37200e' - 'c3af5556d9d872f7d2316728e67a7a9cb77041b687e517a906f03e14a4e58e54') + 'fcdde6d5b82ee4136bf848d0c15fd3ce9ad1c49b58208cd625e1d5d42b9d244f' + '631c3fd1fea46ab9b110eaea6cfa3ed5d7098152858bb082bf66853c1ef600d2' + 'aa44352a89daa2498ed441c4538e8bbcb651ff4804ad1c805830c1f61590e4d5' + 'a49120a04cb6d4276f03d0e86d755cf9ab32bb7ab916ad985a89862c0a35f05d' + '1bb9c0cf2e0dfc139705fc9fac49ff34247c3165ca3f5017dd96c22ff7c7cc60' + '51917f768432de254f1a554a33fbe988255203dc661a92fd089cda1520be4b08' + 'db9ad75ac934a40eac39721e2df8ca9e9ffb587c3aedb8e368d9f0268840a06d' + '6bdbcaa3a29c599adab4ed7d66ef65d827d137a63c813bd00c2c27592999ba5b' + '2dd8347510f0fe5cafe698d4f63eac7c017d137dd5ce2fcf47c874232485e734' + 'eaaa286bc210bfe79263a9bbf9fa16feff71c57733f9ea1571160dd276f5151e' + '24c14f2719638469feff9f31edf0f00f94ed9c0d226129a9c653927df15f2fb0' + '0188ec1dcb0b86006cde4b964d0952f8b9c77b1794cf99c614d9743869f8aefa' + 'cc1fd9ad9b15baabe33f3361adb97b7b0868a39e1146458e71ce0fa8978e1bca' + '1f30c81a4a60d803f2ff19ad72174010b3fda2edd0d9ebba803de7f8fa77647c' + '3381f58ec4cb0f5ef240e48a31a74af6205be186a1378f4ab706a376f8cc4df2') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index 2eb0fdb85f..eb2c8c3fd2 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.14.config \ No newline at end of file +../../../configs/surface-6.15.config \ No newline at end of file From 63eb85a33b1d0d87255e46685665804de5b3eca7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Jun 2025 02:58:11 +0200 Subject: [PATCH 110/236] Update Debian kernel to v6.15.1 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index f046e15902..ced83f7b6d 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.14.2" +KERNEL_VERSION="6.15.1" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 355704e243b8ba3b5b2ac2a60b01a42e7690e1b8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Jun 2025 13:33:18 +0200 Subject: [PATCH 111/236] pkg/debian: Update Debian-specific patches --- ...secureboot-pre-signing-to-the-kernel.patch | 12 ++++----- ...-integrity-Only-use-machine-keyring-.patch | 4 +-- ...sallow-unprivileged-CLONE_NEWUSER-by.patch | 26 +++++++++---------- ...uild-Copy-config-to-target-directory.patch | 4 +-- ...001-kbuild-Link-sign-file-statically.patch | 4 +-- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch index 2b4b9c8266..bfcedb06b9 100644 --- a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch +++ b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch @@ -1,4 +1,4 @@ -From e4eb5bb44e5ac84958c641f62fcfec5114d03073 Mon Sep 17 00:00:00 2001 +From c9d3ed004787ac580252b06af2642e5bb5aaf265 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 22 Sep 2019 22:44:16 +0200 Subject: [PATCH] Add secureboot pre-signing to the kernel @@ -21,10 +21,10 @@ Signed-off-by: Dorian Stoll create mode 100755 scripts/sign_kernel.sh diff --git a/.gitignore b/.gitignore -index c59dc60ba62e..d60f75150ebf 100644 +index f2f63e47fb88..99638429fcbb 100644 --- a/.gitignore +++ b/.gitignore -@@ -149,6 +149,9 @@ signing_key.priv +@@ -159,6 +159,9 @@ signing_key.priv signing_key.x509 x509.genkey @@ -35,10 +35,10 @@ index c59dc60ba62e..d60f75150ebf 100644 /all.config /alldef.config diff --git a/arch/x86/Makefile b/arch/x86/Makefile -index 801fd85c3ef6..1b1a72179a74 100644 +index 594723005d95..a5c8c487e83d 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile -@@ -302,6 +302,7 @@ endif +@@ -314,6 +314,7 @@ endif $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE) $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@ @@ -83,5 +83,5 @@ index 000000000000..d2526a279254 +sbsign --key $BUILDDIR/keys/MOK.key --cert $BUILDDIR/keys/MOK.crt \ + --output $VMLINUX $VMLINUX -- -2.45.2 +2.50.0 diff --git a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch index a5b4568a8f..b212d6922d 100644 --- a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch +++ b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch @@ -1,4 +1,4 @@ -From 1fb0cb1a5de985b6b8728f6a39660fcd5df29977 Mon Sep 17 00:00:00 2001 +From 020939dbfdd44d08f1da5d9d980ce27176514009 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 22:54:05 +0100 Subject: [PATCH] Partially revert "integrity: Only use machine keyring when @@ -37,5 +37,5 @@ index a401640a63cd..a1ad244cbf86 100644 static bool __init trust_moklist(void) -- -2.49.0 +2.50.0 diff --git a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch index 6ffe47c8d6..232d05d790 100644 --- a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch +++ b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch @@ -1,4 +1,4 @@ -From d70cb56d43efddd10d4263f2af24f52fb81137b9 Mon Sep 17 00:00:00 2001 +From f675a2222ecd97c5b85bf05901e3220ee90c30ba Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Fri, 31 May 2013 19:12:12 +0100 Subject: [PATCH] add sysctl to disallow unprivileged CLONE_NEWUSER by default @@ -20,7 +20,7 @@ Signed-off-by: Serge Hallyn 3 files changed, 32 insertions(+) diff --git a/kernel/fork.c b/kernel/fork.c -index ca2ca3884f76..d9591a8a6ead 100644 +index 168681fc4b25..74abab2c65c1 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -119,6 +119,12 @@ @@ -36,7 +36,7 @@ index ca2ca3884f76..d9591a8a6ead 100644 /* * Minimum number of threads to boot the kernel */ -@@ -2171,6 +2177,10 @@ __latent_entropy struct task_struct *copy_process( +@@ -2194,6 +2200,10 @@ __latent_entropy struct task_struct *copy_process( if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -47,7 +47,7 @@ index ca2ca3884f76..d9591a8a6ead 100644 /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. -@@ -3324,6 +3334,12 @@ int ksys_unshare(unsigned long unshare_flags) +@@ -3354,6 +3364,12 @@ int ksys_unshare(unsigned long unshare_flags) if (unshare_flags & CLONE_NEWNS) unshare_flags |= CLONE_FS; @@ -61,21 +61,21 @@ index ca2ca3884f76..d9591a8a6ead 100644 if (err) goto bad_unshare_out; diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index cb57da499ebb..5e9ae0e6a727 100644 +index 3b7a7308e35b..cb4bab6a39bf 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c -@@ -135,6 +135,10 @@ static enum sysctl_writes_mode sysctl_writes_strict = SYSCTL_WRITES_STRICT; - int sysctl_legacy_va_layout; - #endif +@@ -84,6 +84,10 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals); + static const int ngroups_max = NGROUPS_MAX; + static const int cap_last_cap = CAP_LAST_CAP; +#ifdef CONFIG_USER_NS +extern int unprivileged_userns_clone; +#endif + - #endif /* CONFIG_SYSCTL */ + #ifdef CONFIG_PROC_SYSCTL - /* -@@ -1617,6 +1621,15 @@ static const struct ctl_table kern_table[] = { + /** +@@ -1595,6 +1599,15 @@ static const struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, @@ -92,7 +92,7 @@ index cb57da499ebb..5e9ae0e6a727 100644 { .procname = "tainted", diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c -index aa0b2e47f2f2..222bb2b40b73 100644 +index 682f40d5632d..bf265ad528f9 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -22,6 +22,9 @@ @@ -106,5 +106,5 @@ index aa0b2e47f2f2..222bb2b40b73 100644 static DEFINE_MUTEX(userns_state_mutex); -- -2.49.0 +2.50.0 diff --git a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch index 75376c4af9..88019b6083 100644 --- a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch +++ b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch @@ -1,4 +1,4 @@ -From 95802baf706303292278c2ae4347f5c3aa9dcece Mon Sep 17 00:00:00 2001 +From b62686b48f37ac9a8807d3e26523226ff900c27c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 03:02:20 +0200 Subject: [PATCH] kbuild: Copy config to target directory @@ -20,5 +20,5 @@ index b96538787f3d..718bd64d060e 100755 + find "${destdir}" \( -name '.*.cmd' -o -name '*.o' \) -delete -- -2.49.0 +2.50.0 diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index eee7ae8e73..d9e06ed948 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -1,4 +1,4 @@ -From b1c72eb34eabfd56cbe5a1b98b827aded4917125 Mon Sep 17 00:00:00 2001 +From d31ef20443261b91cc47efbcc749369f5df29c95 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:10:28 +0200 Subject: [PATCH] kbuild: Link sign-file statically @@ -21,5 +21,5 @@ index 46f860529df5..7846e18ef5d8 100644 ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) -- -2.49.0 +2.50.0 From 9dc132ee53c4e2e9120b2b5309f41bdde9b146ee Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 24 Jun 2025 21:34:18 +0200 Subject: [PATCH 112/236] configs: Enable upstream Intel THC driver --- configs/surface-6.14.config | 2 ++ configs/surface-6.15.config | 2 ++ 2 files changed, 4 insertions(+) diff --git a/configs/surface-6.14.config b/configs/surface-6.14.config index d58d539727..a026c661b5 100644 --- a/configs/surface-6.14.config +++ b/configs/surface-6.14.config @@ -37,6 +37,8 @@ CONFIG_SURFACE_HOTPLUG=m ## CONFIG_HID_IPTS=m CONFIG_HID_ITHC=m +CONFIG_INTEL_THC_HID=m +CONFIG_INTEL_QUICKSPI=m ## ## Cameras: IPU3 diff --git a/configs/surface-6.15.config b/configs/surface-6.15.config index d58d539727..a026c661b5 100644 --- a/configs/surface-6.15.config +++ b/configs/surface-6.15.config @@ -37,6 +37,8 @@ CONFIG_SURFACE_HOTPLUG=m ## CONFIG_HID_IPTS=m CONFIG_HID_ITHC=m +CONFIG_INTEL_THC_HID=m +CONFIG_INTEL_QUICKSPI=m ## ## Cameras: IPU3 From 8b19fa2465d7a6eb50220713fd985970e777fe8f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 24 Jun 2025 21:35:39 +0200 Subject: [PATCH 113/236] Bump Arch pkgrel --- pkg/arch/kernel/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 4d436f7920..0e82bc28da 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -4,7 +4,7 @@ pkgbase=linux-surface pkgver=6.15.3.arch1 -pkgrel=1 +pkgrel=2 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -59,7 +59,7 @@ validpgpkeys=( ) sha256sums=('13443654c25cebb5b3e462a02cdb9b5cd47fe3e45331f06440a9c0d9e9236e7b' 'a6a234cd982d21f0d7daa3ba921293e450abd87ff5d7474d4a153b3f34cfabc5' - '8a68dbf5e7875f0d6a99c6aeb1dc913cc320fcb4e29c7fe388dc2ed7d81ac76b' + 'ee110be98c41a45302b2b81b037e3c4392ea7f142282e28400ac67b37455d42a' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' 'fcdde6d5b82ee4136bf848d0c15fd3ce9ad1c49b58208cd625e1d5d42b9d244f' '631c3fd1fea46ab9b110eaea6cfa3ed5d7098152858bb082bf66853c1ef600d2' From 95cec14cb77f9a3587b3eba658765d5e6c2f025f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 24 Jun 2025 21:36:55 +0200 Subject: [PATCH 114/236] Update Fedora kernels to v6.15.3 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 6dae8eceaf..6bfb514426 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.14.11-0" +PACKAGE_TAG = "kernel-6.15.3-0" ## ## The release number of the modified kernel package. From e85a7cf8915d96b413b0f1f3bd0680d83635af80 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 24 Jun 2025 21:37:30 +0200 Subject: [PATCH 115/236] Bump Debian pkgrel --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index ced83f7b6d..ccc1b45889 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ KERNEL_VERSION="6.15.1" -KERNEL_REVISION="1" +KERNEL_REVISION="2" KERNEL_LOCALVERSION="-surface" From df09fd5d4d22ab4506a09e432cbdc9c647471777 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 25 Jun 2025 21:54:23 +0200 Subject: [PATCH 116/236] pkg/fedora: Update Fedora-specific build patches --- ...-Pull-in-iptsd-as-a-weak-dependency.patch} | 8 ++-- ...e-provide-the-standard-package-name.patch} | 18 ++++----- ...e-conflict-with-older-versions-of-t.patch} | 39 +++++++------------ ...nd-service-files-for-keeping-the-su.patch} | 18 ++++----- ... => 0005-Pull-in-intel-vsc-firmware.patch} | 8 ++-- 5 files changed, 41 insertions(+), 50 deletions(-) rename pkg/fedora/kernel-surface/patches/{0001-iptsd.patch => 0001-Pull-in-iptsd-as-a-weak-dependency.patch} (80%) rename pkg/fedora/kernel-surface/patches/{0002-provides.patch => 0002-Let-kernel-surface-provide-the-standard-package-name.patch} (78%) rename pkg/fedora/kernel-surface/patches/{0003-obsoletes.patch => 0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch} (71%) rename pkg/fedora/kernel-surface/patches/{0004-default-kernel.patch => 0004-Install-scripts-and-service-files-for-keeping-the-su.patch} (87%) rename pkg/fedora/kernel-surface/patches/{0005-ipu3-fw.patch => 0005-Pull-in-intel-vsc-firmware.patch} (80%) diff --git a/pkg/fedora/kernel-surface/patches/0001-iptsd.patch b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch similarity index 80% rename from pkg/fedora/kernel-surface/patches/0001-iptsd.patch rename to pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch index 3bc6dc4a72..4c80306421 100644 --- a/pkg/fedora/kernel-surface/patches/0001-iptsd.patch +++ b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch @@ -1,4 +1,4 @@ -From 7edf2d0d7cb87dc6c1af96d6d5cb2b0c906261d6 Mon Sep 17 00:00:00 2001 +From a6efddbe9af597841afae20b6f046f96b5467609 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:33:03 +0200 Subject: [PATCH 1/5] Pull in iptsd as a weak dependency @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index c0201430e851..a24eae4e25e4 100644 +index 7cc72d5a5c77..c11232e74d15 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1043,6 +1043,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1140,6 +1140,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index c0201430e851..a24eae4e25e4 100644 Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -- -2.47.0 +2.50.0 diff --git a/pkg/fedora/kernel-surface/patches/0002-provides.patch b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch similarity index 78% rename from pkg/fedora/kernel-surface/patches/0002-provides.patch rename to pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch index 3e5e86c4ca..d885aecd5f 100644 --- a/pkg/fedora/kernel-surface/patches/0002-provides.patch +++ b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch @@ -1,4 +1,4 @@ -From 41770a97d1ea6e590697a6c3319b2d39581eab4d Mon Sep 17 00:00:00 2001 +From 1d878cc13b3d4d5d50ad58b9a871ad2202a9c7ec Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:34:38 +0200 Subject: [PATCH 2/5] Let kernel-surface provide the standard package names @@ -9,18 +9,18 @@ Signed-off-by: Dorian Stoll 1 file changed, 5 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index a24eae4e25e4..3b6c46b930e7 100644 +index c11232e74d15..ca6517bdc945 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -665,6 +665,7 @@ Requires: kernel-core-uname-r = %{KVERREL} - Requires: kernel-modules-uname-r = %{KVERREL} +@@ -723,6 +723,7 @@ Requires: kernel-modules-uname-r = %{KVERREL} Requires: kernel-modules-core-uname-r = %{KVERREL} + Requires: ((kernel-modules-extra-uname-r = %{KVERREL}) if kernel-modules-extra-matched) Provides: installonlypkg(kernel) +Provides: kernel = %{KVERREL} %endif -@@ -1375,6 +1376,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} +@@ -1440,6 +1441,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} Provides: kernel%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release}\ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1:+%{1}}}\ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -28,7 +28,7 @@ index a24eae4e25e4..3b6c46b930e7 100644 Provides: installonlypkg(kernel)\ AutoReqProv: no\ Requires(pre): findutils\ -@@ -1404,6 +1406,7 @@ against the %{?2:%{2} }kernel package.\ +@@ -1469,6 +1471,7 @@ against the %{?2:%{2} }kernel package.\ Summary: Meta package to install matching core and devel packages for a given %{?2:%{2} }kernel\ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ @@ -36,7 +36,7 @@ index a24eae4e25e4..3b6c46b930e7 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1525,6 +1528,7 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ +@@ -1586,6 +1589,7 @@ Requires: ((kernel-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) Requires: realtime-setup\ %endif\ Provides: installonlypkg(kernel)\ @@ -44,7 +44,7 @@ index a24eae4e25e4..3b6c46b930e7 100644 %description %{1}\ The meta-package for the %{1} kernel\ %{nil} -@@ -1558,6 +1562,7 @@ This package provides KVM modules for package kernel%{?1:-%{1}}.\ +@@ -1600,6 +1604,7 @@ The meta-package for the %{1} kernel\ Summary: %{variant_summary}\ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: installonlypkg(kernel)\ @@ -53,5 +53,5 @@ index a24eae4e25e4..3b6c46b930e7 100644 Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ -- -2.47.0 +2.50.0 diff --git a/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch similarity index 71% rename from pkg/fedora/kernel-surface/patches/0003-obsoletes.patch rename to pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch index 52f1c5d18b..85ed833c66 100644 --- a/pkg/fedora/kernel-surface/patches/0003-obsoletes.patch +++ b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch @@ -1,4 +1,4 @@ -From 4da3688eddb23be31b8560e6c437fd7fe86ad809 Mon Sep 17 00:00:00 2001 +From cb7cebc53abc4152d3db1e3e53b069792dd3171e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:40:32 +0200 Subject: [PATCH 3/5] Let kernel-surface conflict with older versions of the @@ -6,15 +6,15 @@ Subject: [PATCH 3/5] Let kernel-surface conflict with older versions of the Signed-off-by: Dorian Stoll --- - redhat/kernel.spec.template | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) + redhat/kernel.spec.template | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 3b6c46b930e7..3b44b904b025 100644 +index ca6517bdc945..2be57434622c 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -666,6 +666,10 @@ Requires: kernel-modules-uname-r = %{KVERREL} - Requires: kernel-modules-core-uname-r = %{KVERREL} +@@ -724,6 +724,10 @@ Requires: kernel-modules-core-uname-r = %{KVERREL} + Requires: ((kernel-modules-extra-uname-r = %{KVERREL}) if kernel-modules-extra-matched) Provides: installonlypkg(kernel) Provides: kernel = %{KVERREL} + @@ -24,7 +24,7 @@ index 3b6c46b930e7..3b44b904b025 100644 %endif -@@ -1378,6 +1382,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff +@@ -1443,6 +1447,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: kernel-devel = %{KVERREL}%{?1:+%{1}}\ Provides: installonlypkg(kernel)\ @@ -33,7 +33,7 @@ index 3b6c46b930e7..3b44b904b025 100644 AutoReqProv: no\ Requires(pre): findutils\ Requires: findutils\ -@@ -1407,6 +1413,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ +@@ -1472,6 +1478,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ Provides: kernel-devel-matched = %{specrpmversion}-%{release}\ @@ -42,16 +42,7 @@ index 3b6c46b930e7..3b44b904b025 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1439,6 +1447,8 @@ Provides: kernel%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix - Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ - Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ - Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ -+Conflicts: %{package_name}-modules-internal < 6.3.7-2\ -+Obsoletes: %{package_name}-modules-internal < 6.3.7-2\ - AutoReq: no\ - AutoProv: yes\ - %description %{?1:%{1}-}modules-internal\ -@@ -1460,6 +1470,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? +@@ -1520,6 +1528,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -60,7 +51,7 @@ index 3b6c46b930e7..3b44b904b025 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-extra-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1483,6 +1495,8 @@ Provides: installonlypkg(kernel-module)\ +@@ -1543,6 +1553,8 @@ Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -69,7 +60,7 @@ index 3b6c46b930e7..3b44b904b025 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1505,6 +1519,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: +@@ -1565,6 +1577,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ @@ -78,8 +69,8 @@ index 3b6c46b930e7..3b44b904b025 100644 %if %{-m:1}%{!-m:0}\ Requires: kernel-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ %endif\ -@@ -1527,6 +1543,8 @@ Requires: kernel-%{1}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{1}}\ - %if "%{1}" == "rt" || "%{1}" == "rt-debug"\ +@@ -1588,6 +1602,8 @@ Requires: ((kernel-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) + %if "%{1}" == "rt" || "%{1}" == "rt-debug" || "%{1}" == "rt-64k" || "%{1}" == "rt-64k-debug"\ Requires: realtime-setup\ %endif\ +Conflicts: %{package_name} < 6.3.7-2\ @@ -87,7 +78,7 @@ index 3b6c46b930e7..3b44b904b025 100644 Provides: installonlypkg(kernel)\ Provides: kernel = %{KVERREL}+%{1}\ %description %{1}\ -@@ -1563,6 +1581,8 @@ Summary: %{variant_summary}\ +@@ -1605,6 +1621,8 @@ Summary: %{variant_summary}\ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Provides: installonlypkg(kernel)\ Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{?1:+%{1}}\ @@ -97,5 +88,5 @@ index 3b6c46b930e7..3b44b904b025 100644 Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ -- -2.47.0 +2.50.0 diff --git a/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch similarity index 87% rename from pkg/fedora/kernel-surface/patches/0004-default-kernel.patch rename to pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch index d61964488c..af0d0dc319 100644 --- a/pkg/fedora/kernel-surface/patches/0004-default-kernel.patch +++ b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch @@ -1,4 +1,4 @@ -From e4184318977732138664afe43f9e1083ed530dc3 Mon Sep 17 00:00:00 2001 +From 9254dd83c5727f0ee761af26bc36edd2f1921010 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:41:11 +0200 Subject: [PATCH 4/5] Install scripts and service files for keeping the surface @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 33 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 3b44b904b025..d4adb18e6024 100644 +index 2be57434622c..e62247d054aa 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1016,6 +1016,11 @@ Source4000: README.rst +@@ -1113,6 +1113,11 @@ Source4000: README.rst Source4001: rpminspect.yaml Source4002: gating.yaml @@ -25,7 +25,7 @@ index 3b44b904b025..d4adb18e6024 100644 ## Patches needed for building this package %if !%{nopatches} -@@ -1049,6 +1054,7 @@ Requires(pre): %{initrd_prereq}\ +@@ -1146,6 +1151,7 @@ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ Recommends: iptsd\ @@ -33,7 +33,7 @@ index 3b44b904b025..d4adb18e6024 100644 Requires(preun): systemd >= 200\ Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -@@ -1063,6 +1069,13 @@ AutoProv: yes\ +@@ -1160,6 +1166,13 @@ AutoProv: yes\ %{nil} @@ -47,7 +47,7 @@ index 3b44b904b025..d4adb18e6024 100644 %package doc Summary: Various documentation bits found in the kernel source Group: Documentation -@@ -3242,6 +3255,11 @@ find Documentation -type d | xargs chmod u+w +@@ -3366,6 +3379,11 @@ find Documentation -type d | xargs chmod u+w cd linux-%{KVERREL} @@ -59,7 +59,7 @@ index 3b44b904b025..d4adb18e6024 100644 # re-define RPM_VMLINUX_H, because it doesn't carry over from %build RPM_VMLINUX_H="$(cat ../vmlinux_h_path)" -@@ -3513,6 +3531,15 @@ popd +@@ -3651,6 +3669,15 @@ popd ### scripts ### @@ -75,7 +75,7 @@ index 3b44b904b025..d4adb18e6024 100644 %if %{with_tools} %post -n %{package_name}-tools-libs /sbin/ldconfig -@@ -3980,6 +4007,12 @@ fi\ +@@ -4118,6 +4145,12 @@ fi\ %{_libexecdir}/kselftests %endif @@ -89,5 +89,5 @@ index 3b44b904b025..d4adb18e6024 100644 %if %{with_up_base} %ifnarch %nobuildarches noarch -- -2.47.0 +2.50.0 diff --git a/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch similarity index 80% rename from pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch rename to pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch index dc5de5d6a6..b8e2bcc8a1 100644 --- a/pkg/fedora/kernel-surface/patches/0005-ipu3-fw.patch +++ b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch @@ -1,4 +1,4 @@ -From 051436f2db94eea7b56a3bf993915b8cc16481f4 Mon Sep 17 00:00:00 2001 +From 53705991e1729c45d4f67442f4f960fac6cbe6fe Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Mon, 29 Jan 2024 19:26:41 +0100 Subject: [PATCH 5/5] Pull in intel-vsc-firmware @@ -9,10 +9,10 @@ This package contains the IPU3 firmware needed for camera support. 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index d4adb18e6024..f236b4807592 100644 +index e62247d054aa..2a649e791854 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1053,6 +1053,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1150,6 +1150,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index d4adb18e6024..f236b4807592 100644 Recommends: %{package_name}-default-watchdog\ Requires(preun): systemd >= 200\ -- -2.47.0 +2.50.0 From 19478d1edba05157d2994ce6debb53ee6f42d2c6 Mon Sep 17 00:00:00 2001 From: Apiznel Date: Fri, 11 Jul 2025 22:49:40 -0400 Subject: [PATCH 117/236] Update v6.15 patches Changes: - Rebase onto v6.15.6 --- patches/6.15/0001-secureboot.patch | 10 ++--- patches/6.15/0002-surface3.patch | 8 ++-- patches/6.15/0003-mwifiex.patch | 16 +++---- patches/6.15/0004-ath10k.patch | 4 +- patches/6.15/0005-ipts.patch | 22 +++++----- patches/6.15/0006-ithc.patch | 8 ++-- patches/6.15/0007-surface-sam.patch | 8 ++-- patches/6.15/0008-surface-sam-over-hid.patch | 8 ++-- patches/6.15/0009-surface-button.patch | 8 ++-- patches/6.15/0010-surface-typecover.patch | 14 +++--- patches/6.15/0011-surface-shutdown.patch | 8 ++-- patches/6.15/0012-surface-gpe.patch | 4 +- patches/6.15/0013-cameras.patch | 46 ++++++++++---------- patches/6.15/0014-amd-gpio.patch | 8 ++-- patches/6.15/0015-rtc.patch | 4 +- 15 files changed, 88 insertions(+), 88 deletions(-) diff --git a/patches/6.15/0001-secureboot.patch b/patches/6.15/0001-secureboot.patch index 3a8196b424..eb5d42029c 100644 --- a/patches/6.15/0001-secureboot.patch +++ b/patches/6.15/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 58aa22bec32223a605375d0aea0a961105ee3e50 Mon Sep 17 00:00:00 2001 +From b7b6e1c879e4b4b3ef6e30564c150bce6ac2e990 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.50.0 +2.50.1 -From ce1b44f9e408c1bc34413c8a4558df3770700340 Mon Sep 17 00:00:00 2001 +From c7f5e7f9f75b8d4f7d2a63322b1685438f5f66fa Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 8f75ec177399..b6c4edfc3c13 100644 +index 76a34e0aef76..e7f3eb39eaf7 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3200,6 +3200,11 @@ @@ -108,5 +108,5 @@ index 5af9c7ee98cd..d52aa94e2fa2 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0002-surface3.patch b/patches/6.15/0002-surface3.patch index 4350edbb97..f138dbe56f 100644 --- a/patches/6.15/0002-surface3.patch +++ b/patches/6.15/0002-surface3.patch @@ -1,4 +1,4 @@ -From c16ae226b323ecaaf85b3313d572af82c1512f79 Mon Sep 17 00:00:00 2001 +From 9195bdae957fb95ddc43eaf1ef314f25efe3ddaa Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,9 +97,9 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.50.0 +2.50.1 -From 6a1dfdbafe59e4c34fa9ea08995fe1fd81a953ff Mon Sep 17 00:00:00 2001 +From f0c58b5eb4a2dc3e5c86cce8ca63c1e59f1b2efd Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -230,5 +230,5 @@ index 6074b7730e86..6aa3e1d6f160 100644 } -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0003-mwifiex.patch b/patches/6.15/0003-mwifiex.patch index 3a7f1a75de..5b508a2242 100644 --- a/patches/6.15/0003-mwifiex.patch +++ b/patches/6.15/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 5edd27f4f92f91b33179da72382d94a7a6e4a724 Mon Sep 17 00:00:00 2001 +From fe4dc0a6c78d5bca34aa98ef19b5a5f39da6fdd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.50.0 +2.50.1 -From 32c223c4870502c93ea3a9546d1485cf06edb253 Mon Sep 17 00:00:00 2001 +From 8cf9feb8d000f8d14a1fab5a167811dee053d99a Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.50.0 +2.50.1 -From 707482723cea399c4434e41d4d2b6745e7840bc1 Mon Sep 17 00:00:00 2001 +From 7640e6841e25dffbc849ed11bb412314c9e08f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 256b451bbe06..ee7767cc1c9e 100644 +index ef9689f87769..09f1b31d27ab 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 256b451bbe06..ee7767cc1c9e 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3990,6 +3992,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3995,6 +3997,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 256b451bbe06..ee7767cc1c9e 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0004-ath10k.patch b/patches/6.15/0004-ath10k.patch index de3891921c..3894d68ff1 100644 --- a/patches/6.15/0004-ath10k.patch +++ b/patches/6.15/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 4c65bd8db7df242e91af6990230b181df8cfa7a7 Mon Sep 17 00:00:00 2001 +From ecbeaa038037c42c93ca3e3e232a7fa0f0b300d0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index 6d336e39d673..d87366371688 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0005-ipts.patch b/patches/6.15/0005-ipts.patch index 48688d6f5d..883fe5c5e5 100644 --- a/patches/6.15/0005-ipts.patch +++ b/patches/6.15/0005-ipts.patch @@ -1,4 +1,4 @@ -From c87b2ec3061da9f24432c8d6a1ffca4429f7aabd Mon Sep 17 00:00:00 2001 +From 0dbc1a49688f32f89b88665ef2f28e07e6d5306c Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -35,9 +35,9 @@ index 3f9c60b579ae..853a67753333 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.50.0 +2.50.1 -From 9a5cea04540ad007abd43f8176cc63a54767c9bd Mon Sep 17 00:00:00 2001 +From f053af438705b0ff4eb429bb332f208f4f31229e Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index cb0b993bebb4..c07d15343f76 100644 +index ff07ee2940f5..a5e75c91734c 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -91,7 +91,7 @@ index cb0b993bebb4..c07d15343f76 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -1935,6 +1942,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1936,6 +1943,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index cb0b993bebb4..c07d15343f76 100644 } return 0; -@@ -2229,6 +2239,9 @@ static int __init init_dmars(void) +@@ -2230,6 +2240,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index cb0b993bebb4..c07d15343f76 100644 check_tylersburg_isoch(); /* -@@ -4430,6 +4443,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4450,6 +4463,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index cb0b993bebb4..c07d15343f76 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4468,6 +4493,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4488,6 +4513,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index cb0b993bebb4..c07d15343f76 100644 { if (risky_device(dev)) -- -2.50.0 +2.50.1 -From c38605effe7f260704799b5c01e541098b3d9267 Mon Sep 17 00:00:00 2001 +From 820744bb81499a033d7d4179c1fbb6e2e6fbd89f Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3239,5 +3239,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0006-ithc.patch b/patches/6.15/0006-ithc.patch index 1624eb6e82..dee711eff1 100644 --- a/patches/6.15/0006-ithc.patch +++ b/patches/6.15/0006-ithc.patch @@ -1,4 +1,4 @@ -From effec31b7d5fc919c1e7c833ecaedfb646149d59 Mon Sep 17 00:00:00 2001 +From df4ecc597bec79e3218e66d792576f61d0b153f5 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index 3bc2a03cceca..e4c95c0a87f9 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.50.0 +2.50.1 -From 6cb26a17c61fade693a12befdcbcb2b47770fc81 Mon Sep 17 00:00:00 2001 +From 5ab09a21afd87cf05a6805b057aabe916bcff944 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -2776,5 +2776,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0007-surface-sam.patch b/patches/6.15/0007-surface-sam.patch index e580134f3c..5002ceaf0d 100644 --- a/patches/6.15/0007-surface-sam.patch +++ b/patches/6.15/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 0309bce8f2832eff001871abbe542a0fa2e08ba2 Mon Sep 17 00:00:00 2001 +From a3f0a11dc5bf640443c1d19454f02d9d2c165bee Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -179,9 +179,9 @@ index 000000000000..f6c17c4e98d5 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.50.0 +2.50.1 -From c48bf4e09c8b09686bf938428dbc48ad192965ea Mon Sep 17 00:00:00 2001 +From 160bffb3504e3a08d815a09cf430243ad201fa63 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -207,5 +207,5 @@ index a594d5fcfcfd..07b03aa4fa7f 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0008-surface-sam-over-hid.patch b/patches/6.15/0008-surface-sam-over-hid.patch index 4bf15cf71c..9e72fe04bb 100644 --- a/patches/6.15/0008-surface-sam-over-hid.patch +++ b/patches/6.15/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From c8d17a0b05fc10ed5025942fb7411b6991cfccfd Mon Sep 17 00:00:00 2001 +From 7ce98975f6d275c074f9032ee121922eaaff8897 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index d2499f302b50..77ce5ec3dd9e 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.50.0 +2.50.1 -From 127b0fcb832e5606d77ca98daa7268b5f5bdf76b Mon Sep 17 00:00:00 2001 +From 5523babd5ca75c0a4871bd92a69c299374b93320 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0009-surface-button.patch b/patches/6.15/0009-surface-button.patch index fef2769d5f..1b3211293c 100644 --- a/patches/6.15/0009-surface-button.patch +++ b/patches/6.15/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 5f6aee8e72a7dbabba5c1cbbc6245a891cbc4ba3 Mon Sep 17 00:00:00 2001 +From 5a39b0e42dcbb09afb3949f3ba3e426aaee6255a Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index b8cad415c62c..43b5d56383e3 100644 /* -- -2.50.0 +2.50.1 -From 21c595df17f9a0d2016cf0285ed78912711bac95 Mon Sep 17 00:00:00 2001 +From 174e231d44a219ec09db0b6cc86c9b9b9e8e5e6d Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0010-surface-typecover.patch b/patches/6.15/0010-surface-typecover.patch index 152ff689e5..0f44a6b386 100644 --- a/patches/6.15/0010-surface-typecover.patch +++ b/patches/6.15/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 9e611153712541c8dde237599028c05ddfc8443d Mon Sep 17 00:00:00 2001 +From a8070b37a0bf6c1803c9abfb5206ad25735610a7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 53d68d20fb62..cf85b30b1d60 100644 +index 0cf94c7a2c9c..115d2628cdb6 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index 53d68d20fb62..cf85b30b1d60 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.50.0 +2.50.1 -From 875ba51655d8bf28f70a2e9e6831d7e454382d48 Mon Sep 17 00:00:00 2001 +From ab4ffb575fb6b1f7424254e24b4e0854b6d2297c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -272,9 +272,9 @@ index 7ac8e16e6158..41017a552681 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.50.0 +2.50.1 -From 4f5ba1c992de1e614aa8dea5412f4835da545a7e Mon Sep 17 00:00:00 2001 +From b160fd9f2794ce51c8d071c48119e40dd47bc4f0 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -571,5 +571,5 @@ index 41017a552681..e1ce20b3bb8f 100644 unregister_pm_notifier(&td->pm_notifier); timer_delete_sync(&td->release_timer); -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0011-surface-shutdown.patch b/patches/6.15/0011-surface-shutdown.patch index 34d4c0ccf3..40dd198cfe 100644 --- a/patches/6.15/0011-surface-shutdown.patch +++ b/patches/6.15/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From d3afc544e9d422f244aba40244a2293e96cba76b Mon Sep 17 00:00:00 2001 +From 2378966d2298b363ffe2fe7eac9aaaf4f26eea89 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -37,10 +37,10 @@ index c8bd71a739f7..0656b4d3e0e5 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 94daca15a096..506d399cda42 100644 +index d0f7b749b9a6..4e572ce73a2f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6316,3 +6316,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6339,3 +6339,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -93,5 +93,5 @@ index 081e5c0a3ddf..e552c8bed5fe 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0012-surface-gpe.patch b/patches/6.15/0012-surface-gpe.patch index 98157ef94b..6565ca95fe 100644 --- a/patches/6.15/0012-surface-gpe.patch +++ b/patches/6.15/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From d2e23db264d326900aebdea72da76f73184f1588 Mon Sep 17 00:00:00 2001 +From d84d983b64ea9a0b22b3880d9427a00730c4c540 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index b359413903b1..b4496db79f39 100644 .ident = "Surface Book 1", .matches = { -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0013-cameras.patch b/patches/6.15/0013-cameras.patch index b1586f5f1a..75479d60b0 100644 --- a/patches/6.15/0013-cameras.patch +++ b/patches/6.15/0013-cameras.patch @@ -1,4 +1,4 @@ -From 673bc3f1e5f697afc8066e59245458935f28546c Mon Sep 17 00:00:00 2001 +From d7a8ba1f35bd8778f60f9b8fc921178477a483eb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index fb1fe9f3b1a3..5be8893b3912 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.50.0 +2.50.1 -From cf8447073f3dee50253c653d9b20ae9cc52a5106 Mon Sep 17 00:00:00 2001 +From c37e3f6ba4be4721a325656cc97b64b77301025f Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index c07d15343f76..f0fd3155340a 100644 +index a5e75c91734c..e5d707a10905 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -132,7 +132,7 @@ index c07d15343f76..f0fd3155340a 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -1943,6 +1952,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1944,6 +1953,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index c07d15343f76..f0fd3155340a 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2239,6 +2251,9 @@ static int __init init_dmars(void) +@@ -2240,6 +2252,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index c07d15343f76..f0fd3155340a 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4443,6 +4458,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4463,6 +4478,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index c07d15343f76..f0fd3155340a 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4493,6 +4520,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4513,6 +4540,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index c07d15343f76..f0fd3155340a 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.50.0 +2.50.1 -From d4df94633dd54daa123fb5497a741d5f0d8d9b9e Mon Sep 17 00:00:00 2001 +From 61c89ac5ab41e85c00827af3ba30a5ba2067cf7b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 81ac4c691963..f453c9043042 100644 return 0; -- -2.50.0 +2.50.1 -From a0ce4892cc5518186d1fb1f54d61aaf7fd4ca64e Mon Sep 17 00:00:00 2001 +From c3c8a3be2c044189765a265ca6ec85b277aeb127 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -258,9 +258,9 @@ index 3226888d77e9..3bfe45b764f7 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.50.0 +2.50.1 -From 75ac36f76af5da0031f58d842158d2a07fc2fe28 Mon Sep 17 00:00:00 2001 +From d42b6cb9654d528bc018218d0235fd3781f843a8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -309,9 +309,9 @@ index cb153ce42c45..f11b499e14bb 100644 if (ret < 0) goto out_cleanup; -- -2.50.0 +2.50.1 -From a726339cb0b04a33e5cf091d7e400e46d3a0fe00 Mon Sep 17 00:00:00 2001 +From 38002558e074b628d78cc3fee9a27e063d2f98c7 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -350,9 +350,9 @@ index f453c9043042..b8ad6b413e8b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.50.0 +2.50.1 -From 15ebc12622ba3d93a9f554e927a63e9e8672f40b Mon Sep 17 00:00:00 2001 +From a3b8fbb54adcb82e9d3c60032d8b8818ecbb08d3 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -391,9 +391,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.50.0 +2.50.1 -From 726379fff106ed4f53dd44877af3a23fd879145c Mon Sep 17 00:00:00 2001 +From 6ab1105d05bd2c4cd64744390d27a229078d45b2 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -642,9 +642,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.50.0 +2.50.1 -From 2e92d47015628f6ed7e3fbd68f2df381fb739876 Mon Sep 17 00:00:00 2001 +From 5bc63841857aa754c76d7bf5834c0e77262ebdab Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -674,5 +674,5 @@ index 032fbcb981f2..e03a1d8cdcb4 100644 cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); fsleep(100); -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0014-amd-gpio.patch b/patches/6.15/0014-amd-gpio.patch index f0f6f2f55a..e313afc828 100644 --- a/patches/6.15/0014-amd-gpio.patch +++ b/patches/6.15/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From d259acfe5ae92dee7a87903b9ec114707d32a887 Mon Sep 17 00:00:00 2001 +From cfbefb2a747f6b74f344010e5f19127905665cb4 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 9fa321a95eb3..8914a922be2b 100644 mp_config_acpi_legacy_irqs(); -- -2.50.0 +2.50.1 -From 45731a8b193e36dfe5987a635bb69088dc9cc4b6 Mon Sep 17 00:00:00 2001 +From 2b6f6c6427e1ff8d84380395bb89490d3ec2b795 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 8914a922be2b..c43d0a553867 100644 }; -- -2.50.0 +2.50.1 diff --git a/patches/6.15/0015-rtc.patch b/patches/6.15/0015-rtc.patch index 6948e9f154..3752a5dbcd 100644 --- a/patches/6.15/0015-rtc.patch +++ b/patches/6.15/0015-rtc.patch @@ -1,4 +1,4 @@ -From 3f0e0d5ea7b1ac2508a86d1abbef5a346ee4fe4e Mon Sep 17 00:00:00 2001 +From 4aa3d0d5e53d533c198d2eb0568ec294889856ca Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 825c2a8acea4..74612088ac5f 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.50.0 +2.50.1 From 35e61696ebde1cef24dfc9477d851e2bafd994ce Mon Sep 17 00:00:00 2001 From: Apiznel Date: Mon, 18 Aug 2025 15:17:04 -0400 Subject: [PATCH 118/236] Update v6.16 patches Changes: - Rebase onto v6.16.1 --- patches/6.16/0001-secureboot.patch | 112 + patches/6.16/0002-surface3.patch | 234 ++ patches/6.16/0003-mwifiex.patch | 400 +++ patches/6.16/0004-ath10k.patch | 120 + patches/6.16/0005-ipts.patch | 3243 ++++++++++++++++++ patches/6.16/0006-ithc.patch | 2780 +++++++++++++++ patches/6.16/0007-surface-sam.patch | 211 ++ patches/6.16/0008-surface-sam-over-hid.patch | 308 ++ patches/6.16/0009-surface-button.patch | 149 + patches/6.16/0010-surface-typecover.patch | 575 ++++ patches/6.16/0011-surface-shutdown.patch | 97 + patches/6.16/0012-surface-gpe.patch | 51 + patches/6.16/0013-cameras.patch | 678 ++++ patches/6.16/0014-amd-gpio.patch | 109 + patches/6.16/0015-rtc.patch | 110 + 15 files changed, 9177 insertions(+) create mode 100644 patches/6.16/0001-secureboot.patch create mode 100644 patches/6.16/0002-surface3.patch create mode 100644 patches/6.16/0003-mwifiex.patch create mode 100644 patches/6.16/0004-ath10k.patch create mode 100644 patches/6.16/0005-ipts.patch create mode 100644 patches/6.16/0006-ithc.patch create mode 100644 patches/6.16/0007-surface-sam.patch create mode 100644 patches/6.16/0008-surface-sam-over-hid.patch create mode 100644 patches/6.16/0009-surface-button.patch create mode 100644 patches/6.16/0010-surface-typecover.patch create mode 100644 patches/6.16/0011-surface-shutdown.patch create mode 100644 patches/6.16/0012-surface-gpe.patch create mode 100644 patches/6.16/0013-cameras.patch create mode 100644 patches/6.16/0014-amd-gpio.patch create mode 100644 patches/6.16/0015-rtc.patch diff --git a/patches/6.16/0001-secureboot.patch b/patches/6.16/0001-secureboot.patch new file mode 100644 index 0000000000..c8de95e127 --- /dev/null +++ b/patches/6.16/0001-secureboot.patch @@ -0,0 +1,112 @@ +From 31b55a34f02fd0f89b035b5869ae17b9030373b0 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index e1f4fd5bc8ee..64f8dc548045 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLLCHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.50.1 + +From 36688672f7609811066f521600e9e39230038f7e Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index f6d317e1674d..21351e253cb2 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3243,6 +3243,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 9216e3b91d3b..ff774a584022 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -38,6 +38,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -98,7 +99,7 @@ bool hibernation_in_progress(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1456,6 +1457,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1513,3 +1520,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.50.1 + diff --git a/patches/6.16/0002-surface3.patch b/patches/6.16/0002-surface3.patch new file mode 100644 index 0000000000..cb761a6b27 --- /dev/null +++ b/patches/6.16/0002-surface3.patch @@ -0,0 +1,234 @@ +From 0a5a737452cff78ac984b95fad50dc1da97da7f6 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3 +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index 6c8fb7a4dde4..22797a53f4d8 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 29a403526cd9..986f32132c3d 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3792,6 +3792,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.50.1 + +From f1f0eecb0b055bc8cc328695dd47103f482f3872 Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Fri, 6 Dec 2019 23:10:30 +0900 +Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by + default + +On Arch Linux kernel at least after 4.19, touch input is broken after suspend +(s2idle). + + kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + +On recent stable Arch Linux kernel (at least after 5.1), touch input will +crash after the first touch. + + kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue + +I found on an affected system (Arch Linux kernel, etc.), the touchscreen +driver uses DMA mode by default. Then, we found some kernels with different +kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel +chromeos-4.19 [2]) will use PIO mode by default and no such issues there. + +So, this commit disables DMA mode on the touchscreen driver side as a quick +workaround to avoid touch input crash. +We may need to properly set up DMA mode to use the touchscreen driver with +DMA mode. + +You can still switch DMA/PIO mode if you want: + + switch to DMA mode (maybe broken) + echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma + back to PIO mode + echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma + +Link to issue: https://github.com/jakeday/linux-surface/issues/596 + +References: +[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config +[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 + +Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. +This commit made the driver use PIO by default and no touch input crash. +Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default +even without this commit. After this commit, it still uses PIO and confirmed +no functional changes regarding touch input. + +More details: + We can confirm which mode the touchscreen driver uses; first, enable + debug output: + + echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + + Then, try to make a touch input and see dmesg log + + (On Arch Linux kernel, uses DMA) + kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA + kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 + c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + + (On the kernels I referenced above, uses PIO) + kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO + kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 + 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Note (2025-03-08): This patch was originally dropped due to the +comments in [3]. However, according to the commments in [4] it is still +required. + +[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a +[4]: https://github.com/linux-surface/linux-surface/issues/1184 + +Patchset: surface3 +--- + drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c +index 6074b7730e86..6aa3e1d6f160 100644 +--- a/drivers/input/touchscreen/surface3_spi.c ++++ b/drivers/input/touchscreen/surface3_spi.c +@@ -25,6 +25,12 @@ + #define SURFACE3_REPORT_TOUCH 0xd2 + #define SURFACE3_REPORT_PEN 0x16 + ++bool use_dma = false; ++module_param(use_dma, bool, 0644); ++MODULE_PARM_DESC(use_dma, ++ "Disable DMA mode if you encounter touch input crash. " ++ "(default: false, disabled to avoid crash)"); ++ + struct surface3_ts_data { + struct spi_device *spi; + struct gpio_desc *gpiod_rst[2]; +@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) + return 0; + } + ++static bool surface3_spi_can_dma(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) ++{ ++ return use_dma; ++} ++ + static int surface3_spi_probe(struct spi_device *spi) + { + struct surface3_ts_data *data; +@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) + if (error) + return error; + ++ /* ++ * Set up DMA ++ * ++ * TODO: Currently, touch input with DMA seems to be broken. ++ * On 4.19 LTS, touch input will crash after suspend. ++ * On recent stable kernel (at least after 5.1), touch input will crash after ++ * the first touch. No problem with PIO on those kernels. ++ * Maybe we need to configure DMA here. ++ * ++ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 ++ */ ++ spi->controller->can_dma = surface3_spi_can_dma; ++ + return 0; + } + +-- +2.50.1 + diff --git a/patches/6.16/0003-mwifiex.patch b/patches/6.16/0003-mwifiex.patch new file mode 100644 index 0000000000..9f7fc19a19 --- /dev/null +++ b/patches/6.16/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From 41b114b1636bdd55c952e21d752c9d020e44c952 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index a760de191fce..db9b203226a8 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.50.1 + +From 586fd6566d18606b857c823f271d74172c1cea40 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index db9b203226a8..ffd0c1fe9223 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.50.1 + +From 68e3fb977dd163d6344ea5cf1a5248d33353976c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index e8977fff4212..d16c47e6df0f 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -469,6 +470,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -4076,6 +4078,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.50.1 + diff --git a/patches/6.16/0004-ath10k.patch b/patches/6.16/0004-ath10k.patch new file mode 100644 index 0000000000..fa08939990 --- /dev/null +++ b/patches/6.16/0004-ath10k.patch @@ -0,0 +1,120 @@ +From 94aced4a2343f676d6d6909af57fdcc867b04a46 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index fe3a8f4a1cc1..06f7bba95bc3 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -40,6 +40,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.50.1 + diff --git a/patches/6.16/0005-ipts.patch b/patches/6.16/0005-ipts.patch new file mode 100644 index 0000000000..8500d22082 --- /dev/null +++ b/patches/6.16/0005-ipts.patch @@ -0,0 +1,3243 @@ +From ff5ea37cd3d84e04e2563a61004ddc81c13d20e8 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index bc40b940ae21..45fbd856d416 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 3f9c60b579ae..853a67753333 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.50.1 + +From 8571d8878e37c95486ba4d2b5c68c226372c57a7 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index c0be0b64e4c7..04bf55541281 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -39,6 +39,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -207,12 +212,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -1885,6 +1892,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2175,6 +2185,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4398,6 +4411,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4436,6 +4461,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.50.1 + +From 03cbd44a2e522b8c77f560810cb992e1d2e0416a Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 43859fc75747..ded8868dcfea 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1429,6 +1429,8 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 10ae5dedbd84..7ba7d26391e9 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -175,3 +175,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.50.1 + diff --git a/patches/6.16/0006-ithc.patch b/patches/6.16/0006-ithc.patch new file mode 100644 index 0000000000..8320c2b2f4 --- /dev/null +++ b/patches/6.16/0006-ithc.patch @@ -0,0 +1,2780 @@ +From c0b6befe8895c4e40e25568027171fbe5e03fb95 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index cf7b6882ec75..55ab16865774 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -380,6 +380,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.50.1 + +From 67ffc2306c491a00557b995631819f5924a2bc7d Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 438 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2575 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index ded8868dcfea..d6bc87be4854 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1431,6 +1431,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 7ba7d26391e9..d939da7ac2e8 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -177,3 +177,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..094d878d671b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,438 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) }, ++ // MTL and up are handled by drivers/hid/intel-thc-hid ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ timer_delete_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.50.1 + diff --git a/patches/6.16/0007-surface-sam.patch b/patches/6.16/0007-surface-sam.patch new file mode 100644 index 0000000000..73633bce42 --- /dev/null +++ b/patches/6.16/0007-surface-sam.patch @@ -0,0 +1,211 @@ +From 171bc5acbbdaa975f8695af30f208d7facb21eef Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 17 Jun 2022 02:14:00 +0200 +Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator + Module + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/rtc/Kconfig | 7 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 drivers/rtc/rtc-surface.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 9aec922613ce..cd7071b17616 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1376,6 +1376,13 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_SURFACE ++ tristate "Microsoft Surface Aggregator RTC" ++ depends on SURFACE_AGGREGATOR ++ depends on SURFACE_AGGREGATOR_BUS ++ help ++ TODO ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 4619aa2ac469..58f1774c7368 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -181,6 +181,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o + obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o + obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o + obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o ++obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o +diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c +new file mode 100644 +index 000000000000..f6c17c4e98d5 +--- /dev/null ++++ b/drivers/rtc/rtc-surface.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * AC driver for 7th-generation Microsoft Surface devices via Surface System ++ * Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2019-2021 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct surface_rtc { ++ struct ssam_device *sdev; ++ struct rtc_device *rtc; ++}; ++ ++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x10, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x0f, ++}); ++ ++static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) ++{ ++ __le32 time_le; ++ int status; ++ ++ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); ++ if (status) ++ return status; ++ ++ *time = le32_to_cpu(time_le); ++ return 0; ++} ++ ++static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) ++{ ++ __le32 time_le = cpu_to_le32(time); ++ ++ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); ++} ++ ++static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ int status; ++ u32 time; ++ ++ status = ssam_rtc_get_unix_time(srtc, &time); ++ if (status) ++ return status; ++ ++ rtc_time64_to_tm(time, tm); ++ return 0; ++} ++ ++static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ time64_t time = rtc_tm_to_time64(tm); ++ ++ return ssam_rtc_set_unix_time(srtc, (u32)time); ++} ++ ++static const struct rtc_class_ops surface_rtc_ops = { ++ .read_time = surface_rtc_read_time, ++ .set_time = surface_rtc_set_time, ++}; ++ ++static int surface_rtc_probe(struct ssam_device *sdev) ++{ ++ struct surface_rtc *srtc; ++ ++ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->sdev = sdev; ++ ++ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); ++ if (IS_ERR(srtc->rtc)) ++ return PTR_ERR(srtc->rtc); ++ ++ srtc->rtc->ops = &surface_rtc_ops; ++ srtc->rtc->range_max = U32_MAX; ++ ++ ssam_device_set_drvdata(sdev, srtc); ++ ++ return devm_rtc_register_device(srtc->rtc); ++} ++ ++static void surface_rtc_remove(struct ssam_device *sdev) ++{ ++ /* Device-managed allocations take care of everything... */ ++} ++ ++static const struct ssam_device_id surface_rtc_match[] = { ++ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, surface_rtc_match); ++ ++static struct ssam_device_driver surface_rtc_driver = { ++ .probe = surface_rtc_probe, ++ .remove = surface_rtc_remove, ++ .match_table = surface_rtc_match, ++ .driver = { ++ .name = "surface_rtc", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(surface_rtc_driver); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.50.1 + +From 4ad519e396f03823a1703c67626c8aee216738c1 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 20 Apr 2025 01:05:14 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 + (ACPI) + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index a594d5fcfcfd..07b03aa4fa7f 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Laptop 6 */ + { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + ++ /* Surface Laptop 7 */ ++ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.50.1 + diff --git a/patches/6.16/0008-surface-sam-over-hid.patch b/patches/6.16/0008-surface-sam-over-hid.patch new file mode 100644 index 0000000000..52c1e51764 --- /dev/null +++ b/patches/6.16/0008-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From 08d1c56b91078576f586b8ee8486fe923edd0ef6 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index d2499f302b50..77ce5ec3dd9e 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -661,6 +661,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -762,6 +783,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.50.1 + +From ac87ea167ba39b5a64b4b5ddd19995f1b17bcd96 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index f775c6ca1ec1..2075e3852053 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.50.1 + diff --git a/patches/6.16/0009-surface-button.patch b/patches/6.16/0009-surface-button.patch new file mode 100644 index 0000000000..96ee92a90e --- /dev/null +++ b/patches/6.16/0009-surface-button.patch @@ -0,0 +1,149 @@ +From fa6b68c8fc4730eae6ab0da7e556500d5ee0d7bd Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index b8cad415c62c..43b5d56383e3 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.50.1 + +From b8a8524062bafde8551aa43b7e7cec037be6d775 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.50.1 + diff --git a/patches/6.16/0010-surface-typecover.patch b/patches/6.16/0010-surface-typecover.patch new file mode 100644 index 0000000000..c078b6f0aa --- /dev/null +++ b/patches/6.16/0010-surface-typecover.patch @@ -0,0 +1,575 @@ +From 7cb8f7223f9deffff0c8f56d4c6e07e58aff3e50 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 0cf94c7a2c9c..115d2628cdb6 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.50.1 + +From 8d42e72cdbdff8d754caecc3e1e51b9f5d6b032f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index a1c54ffe02b4..3acf2719cea4 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -35,7 +35,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -73,12 +77,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -176,6 +183,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -220,6 +229,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_GOOGLE 0x0111 + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -410,6 +420,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1759,6 +1779,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1782,6 +1865,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1820,8 +1906,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); +@@ -1830,8 +1918,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1881,6 +1971,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2320,6 +2411,11 @@ static const struct hid_device_id mt_devices[] = { + MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, + USB_DEVICE_ID_XIROKU_CSR2) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.50.1 + +From 27fe08e59a1e4e1c16fe3724bc43be188c85ba6e Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 3acf2719cea4..a359afb687af 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -85,6 +86,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -422,6 +425,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1403,6 +1407,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1430,6 +1437,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1451,6 +1473,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1458,6 +1481,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1467,11 +1503,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1646,6 +1692,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1694,6 +1776,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1779,30 +1868,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1811,8 +1876,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -1949,13 +2015,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -1964,12 +2041,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); +-- +2.50.1 + diff --git a/patches/6.16/0011-surface-shutdown.patch b/patches/6.16/0011-surface-shutdown.patch new file mode 100644 index 0000000000..fda7911d93 --- /dev/null +++ b/patches/6.16/0011-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 4e3a09a8d12d4e20529e1f2d4d94552478b6f05b Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 01e6aea1b0c7..43d38767f773 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index db6e142b082d..c9bb44f2b37e 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6337,3 +6337,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 05e68f35f392..cc50c771481e 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -478,6 +478,7 @@ struct pci_dev { + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ + unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.50.1 + diff --git a/patches/6.16/0012-surface-gpe.patch b/patches/6.16/0012-surface-gpe.patch new file mode 100644 index 0000000000..e5fe78880a --- /dev/null +++ b/patches/6.16/0012-surface-gpe.patch @@ -0,0 +1,51 @@ +From 48ee98b4ea3d491f1dde163053200cf0bc7eea9e Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index b359413903b1..b4496db79f39 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.50.1 + diff --git a/patches/6.16/0013-cameras.patch b/patches/6.16/0013-cameras.patch new file mode 100644 index 0000000000..179c553245 --- /dev/null +++ b/patches/6.16/0013-cameras.patch @@ -0,0 +1,678 @@ +From a3228469f0d8004a18e50bde7daaff298e0211a6 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index fb1fe9f3b1a3..5be8893b3912 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2197,6 +2197,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.50.1 + +From b6739021e214bf8a47c1774e9d348712a19117a3 Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 04bf55541281..5a8cac788e5a 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -44,6 +44,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -213,12 +220,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -1893,6 +1902,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2185,6 +2197,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4411,6 +4426,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4461,6 +4488,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.50.1 + +From d97d4bdb6b030eca0e4f1b9e6d36333cd115b6c9 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 0133405697dc..9e0763bdc758 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.50.1 + +From ac22813bbf6f8879a522658ff81e0eccce9d75c4 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 3226888d77e9..3bfe45b764f7 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1574,7 +1574,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.50.1 + +From 0b628eac9ac467c74574b290cd8037ca6b1f45b4 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index cb153ce42c45..f11b499e14bb 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.50.1 + +From e013334172ad4602e22121ee39d1b7f20dbbcdbd Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 9e0763bdc758..0976b267972b 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.50.1 + +From a6cd8999b346837ae7c30e4ea252968ac040b46a Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.50.1 + +From 1c74a4a3d26452bdfb6d56afc2c528e48239c8c8 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 6e3dce7e35a4..5b6ba103867c 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -1002,6 +1002,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 9a0333ec1a86..4e1ca8fc9b41 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_UPBOARD) += leds-upboard.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.50.1 + +From 24642c6d23f656ba43bc0b858f04731b5eb27819 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index 032fbcb981f2..e03a1d8cdcb4 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -87,6 +87,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); + fsleep(100); +-- +2.50.1 + diff --git a/patches/6.16/0014-amd-gpio.patch b/patches/6.16/0014-amd-gpio.patch new file mode 100644 index 0000000000..3d91e4afb2 --- /dev/null +++ b/patches/6.16/0014-amd-gpio.patch @@ -0,0 +1,109 @@ +From 3e91eba1c6da22e8fdd0fe6a7a59895c2210ebe3 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 9fa321a95eb3..8914a922be2b 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1171,6 +1172,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1227,6 +1239,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.50.1 + +From 6a2df6666086e15b15661dca7782b02689ccdd34 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 8914a922be2b..c43d0a553867 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.50.1 + diff --git a/patches/6.16/0015-rtc.patch b/patches/6.16/0015-rtc.patch new file mode 100644 index 0000000000..144144b21a --- /dev/null +++ b/patches/6.16/0015-rtc.patch @@ -0,0 +1,110 @@ +From 6a7a9e768afa2d659be5457a85788db87008a7b9 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 825c2a8acea4..74612088ac5f 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.50.1 + From 5fb75c5b2e7c76ac401468d16dfbe72241cdd546 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Sep 2025 10:46:20 +0200 Subject: [PATCH 119/236] Update v6.15 patches Changes: - Rebase onto v6.15.11 Links: - kernel: https://github.com/linux-surface/kernel/commit/4efd7541364fab4008d8bc1ec669156e2b638094 --- patches/6.15/0001-secureboot.patch | 8 ++-- patches/6.15/0002-surface3.patch | 8 ++-- patches/6.15/0003-mwifiex.patch | 16 +++---- patches/6.15/0004-ath10k.patch | 6 +-- patches/6.15/0005-ipts.patch | 22 +++++----- patches/6.15/0006-ithc.patch | 8 ++-- patches/6.15/0007-surface-sam.patch | 8 ++-- patches/6.15/0008-surface-sam-over-hid.patch | 14 +++--- patches/6.15/0009-surface-button.patch | 8 ++-- patches/6.15/0010-surface-typecover.patch | 18 ++++---- patches/6.15/0011-surface-shutdown.patch | 14 +++--- patches/6.15/0012-surface-gpe.patch | 4 +- patches/6.15/0013-cameras.patch | 46 ++++++++++---------- patches/6.15/0014-amd-gpio.patch | 8 ++-- patches/6.15/0015-rtc.patch | 4 +- 15 files changed, 96 insertions(+), 96 deletions(-) diff --git a/patches/6.15/0001-secureboot.patch b/patches/6.15/0001-secureboot.patch index eb5d42029c..06a16c27fe 100644 --- a/patches/6.15/0001-secureboot.patch +++ b/patches/6.15/0001-secureboot.patch @@ -1,4 +1,4 @@ -From b7b6e1c879e4b4b3ef6e30564c150bce6ac2e990 Mon Sep 17 00:00:00 2001 +From bf0b72c5d06f09e4be378295ad67f3c26a9ae39a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.50.1 +2.51.0 -From c7f5e7f9f75b8d4f7d2a63322b1685438f5f66fa Mon Sep 17 00:00:00 2001 +From 1b81b7a3de3b6b5538d11d4c9f78da7801590d1f Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -108,5 +108,5 @@ index 5af9c7ee98cd..d52aa94e2fa2 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0002-surface3.patch b/patches/6.15/0002-surface3.patch index f138dbe56f..9340352408 100644 --- a/patches/6.15/0002-surface3.patch +++ b/patches/6.15/0002-surface3.patch @@ -1,4 +1,4 @@ -From 9195bdae957fb95ddc43eaf1ef314f25efe3ddaa Mon Sep 17 00:00:00 2001 +From 676d973e28a2b248f197b50081a5c7d3dc42823b Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,9 +97,9 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.50.1 +2.51.0 -From f0c58b5eb4a2dc3e5c86cce8ca63c1e59f1b2efd Mon Sep 17 00:00:00 2001 +From 9ccee9531c3c29bc417a85de1cf6a17ca2c51f52 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -230,5 +230,5 @@ index 6074b7730e86..6aa3e1d6f160 100644 } -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0003-mwifiex.patch b/patches/6.15/0003-mwifiex.patch index 5b508a2242..adda69fd5c 100644 --- a/patches/6.15/0003-mwifiex.patch +++ b/patches/6.15/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From fe4dc0a6c78d5bca34aa98ef19b5a5f39da6fdd1 Mon Sep 17 00:00:00 2001 +From 2a55f56c999ac510ec304b8c2aae55bf6de6a788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.50.1 +2.51.0 -From 8cf9feb8d000f8d14a1fab5a167811dee053d99a Mon Sep 17 00:00:00 2001 +From 689175f0a82a58268cc3ac29e00659f6989ef95e Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.50.1 +2.51.0 -From 7640e6841e25dffbc849ed11bb412314c9e08f29 Mon Sep 17 00:00:00 2001 +From aa56d0226f88cdfd12a285e831b336501fef162f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index ef9689f87769..09f1b31d27ab 100644 +index c83de1772fdd..649063398e33 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index ef9689f87769..09f1b31d27ab 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3995,6 +3997,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4012,6 +4014,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index ef9689f87769..09f1b31d27ab 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0004-ath10k.patch b/patches/6.15/0004-ath10k.patch index 3894d68ff1..f583e81d9e 100644 --- a/patches/6.15/0004-ath10k.patch +++ b/patches/6.15/0004-ath10k.patch @@ -1,4 +1,4 @@ -From ecbeaa038037c42c93ca3e3e232a7fa0f0b300d0 Mon Sep 17 00:00:00 2001 +From da3aff48826a9ec1ca4383a32c3886d41d4ec0a7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 6d336e39d673..d87366371688 100644 +index 1adc35e37f40..3d68fe019b3c 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -40,6 +40,9 @@ static bool fw_diag_log; @@ -116,5 +116,5 @@ index 6d336e39d673..d87366371688 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0005-ipts.patch b/patches/6.15/0005-ipts.patch index 883fe5c5e5..56405022f2 100644 --- a/patches/6.15/0005-ipts.patch +++ b/patches/6.15/0005-ipts.patch @@ -1,4 +1,4 @@ -From 0dbc1a49688f32f89b88665ef2f28e07e6d5306c Mon Sep 17 00:00:00 2001 +From 1533f2824f23d3a5c2c9c34ece4fb3bd2b4c35d6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -35,9 +35,9 @@ index 3f9c60b579ae..853a67753333 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.50.1 +2.51.0 -From f053af438705b0ff4eb429bb332f208f4f31229e Mon Sep 17 00:00:00 2001 +From 729712aa7ade4f9211b158ea561fa7e41628b83d Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index ff07ee2940f5..a5e75c91734c 100644 +index 91fe53d671e6..4dc0c206d8a1 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -91,7 +91,7 @@ index ff07ee2940f5..a5e75c91734c 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -1936,6 +1943,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1949,6 +1956,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index ff07ee2940f5..a5e75c91734c 100644 } return 0; -@@ -2230,6 +2240,9 @@ static int __init init_dmars(void) +@@ -2243,6 +2253,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index ff07ee2940f5..a5e75c91734c 100644 check_tylersburg_isoch(); /* -@@ -4450,6 +4463,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4466,6 +4479,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index ff07ee2940f5..a5e75c91734c 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4488,6 +4513,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4504,6 +4529,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index ff07ee2940f5..a5e75c91734c 100644 { if (risky_device(dev)) -- -2.50.1 +2.51.0 -From 820744bb81499a033d7d4179c1fbb6e2e6fbd89f Mon Sep 17 00:00:00 2001 +From 4d065841244d18685f58d9ef74de9babf8267f49 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3239,5 +3239,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0006-ithc.patch b/patches/6.15/0006-ithc.patch index dee711eff1..4cfaf6ad19 100644 --- a/patches/6.15/0006-ithc.patch +++ b/patches/6.15/0006-ithc.patch @@ -1,4 +1,4 @@ -From df4ecc597bec79e3218e66d792576f61d0b153f5 Mon Sep 17 00:00:00 2001 +From 63de3e307ee680676d3bb9870200f5200149a952 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index 3bc2a03cceca..e4c95c0a87f9 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.50.1 +2.51.0 -From 5ab09a21afd87cf05a6805b057aabe916bcff944 Mon Sep 17 00:00:00 2001 +From 1a6a07daa136e37917ca622211c734a0d173deca Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -2776,5 +2776,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0007-surface-sam.patch b/patches/6.15/0007-surface-sam.patch index 5002ceaf0d..402e285a3a 100644 --- a/patches/6.15/0007-surface-sam.patch +++ b/patches/6.15/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From a3f0a11dc5bf640443c1d19454f02d9d2c165bee Mon Sep 17 00:00:00 2001 +From 35f4b75b62840ca63be7ed1d2e141301a2288587 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -179,9 +179,9 @@ index 000000000000..f6c17c4e98d5 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.50.1 +2.51.0 -From 160bffb3504e3a08d815a09cf430243ad201fa63 Mon Sep 17 00:00:00 2001 +From efe6e1411a5b20c8f6d65715d29ce21d14a26c86 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -207,5 +207,5 @@ index a594d5fcfcfd..07b03aa4fa7f 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0008-surface-sam-over-hid.patch b/patches/6.15/0008-surface-sam-over-hid.patch index 9e72fe04bb..a7c5121e4b 100644 --- a/patches/6.15/0008-surface-sam-over-hid.patch +++ b/patches/6.15/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 7ce98975f6d275c074f9032ee121922eaaff8897 Mon Sep 17 00:00:00 2001 +From 4a5332d608cc9203ec450546b2c18b5a1efe2c32 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,10 +55,10 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index d2499f302b50..77ce5ec3dd9e 100644 +index f43067f6797e..1761ca30e17a 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c -@@ -661,6 +661,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, +@@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, return (ret == 1) ? 0 : -EIO; } @@ -86,7 +86,7 @@ index d2499f302b50..77ce5ec3dd9e 100644 static acpi_status i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, -@@ -762,6 +783,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, +@@ -763,6 +784,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, } break; @@ -107,9 +107,9 @@ index d2499f302b50..77ce5ec3dd9e 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.50.1 +2.51.0 -From 5523babd5ca75c0a4871bd92a69c299374b93320 Mon Sep 17 00:00:00 2001 +From c548bea8e95195d03c39cb8ce2fd9f0d5e335da3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0009-surface-button.patch b/patches/6.15/0009-surface-button.patch index 1b3211293c..4984f1a054 100644 --- a/patches/6.15/0009-surface-button.patch +++ b/patches/6.15/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 5a39b0e42dcbb09afb3949f3ba3e426aaee6255a Mon Sep 17 00:00:00 2001 +From cd402996d53de2dcf039c19a187117b22725b417 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index b8cad415c62c..43b5d56383e3 100644 /* -- -2.50.1 +2.51.0 -From 174e231d44a219ec09db0b6cc86c9b9b9e8e5e6d Mon Sep 17 00:00:00 2001 +From 025d75682c2142ff86fb96c5f25506fdf6a4f7fb Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0010-surface-typecover.patch b/patches/6.15/0010-surface-typecover.patch index 0f44a6b386..a2399f15f9 100644 --- a/patches/6.15/0010-surface-typecover.patch +++ b/patches/6.15/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From a8070b37a0bf6c1803c9abfb5206ad25735610a7 Mon Sep 17 00:00:00 2001 +From 0509d466ee9e29adcc75f4adea741140caa53089 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -37,9 +37,9 @@ index 0cf94c7a2c9c..115d2628cdb6 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.50.1 +2.51.0 -From ab4ffb575fb6b1f7424254e24b4e0854b6d2297c Mon Sep 17 00:00:00 2001 +From 1c67b683cbb32077ef4168702aa3c67742e74636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 7ac8e16e6158..41017a552681 100644 +index 536a0a47518f..0a8e70136779 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -259,7 +259,7 @@ index 7ac8e16e6158..41017a552681 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2304,6 +2395,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2310,6 +2401,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -272,9 +272,9 @@ index 7ac8e16e6158..41017a552681 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.50.1 +2.51.0 -From b160fd9f2794ce51c8d071c48119e40dd47bc4f0 Mon Sep 17 00:00:00 2001 +From b5719065b5faa78f2f8cbce4d4197fa3595b7691 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 41017a552681..e1ce20b3bb8f 100644 +index 0a8e70136779..2f46acc170b2 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); @@ -571,5 +571,5 @@ index 41017a552681..e1ce20b3bb8f 100644 unregister_pm_notifier(&td->pm_notifier); timer_delete_sync(&td->release_timer); -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0011-surface-shutdown.patch b/patches/6.15/0011-surface-shutdown.patch index 40dd198cfe..772c36439e 100644 --- a/patches/6.15/0011-surface-shutdown.patch +++ b/patches/6.15/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 2378966d2298b363ffe2fe7eac9aaaf4f26eea89 Mon Sep 17 00:00:00 2001 +From 46248cbac7ca6e688ebe5be29344239c78a884a7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index c8bd71a739f7..0656b4d3e0e5 100644 +index 66e3bea7dc1a..6c30e1f649cd 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,10 +37,10 @@ index c8bd71a739f7..0656b4d3e0e5 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index d0f7b749b9a6..4e572ce73a2f 100644 +index 6e29f2b39dce..2198c761c737 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6339,3 +6339,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6341,3 +6341,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -81,10 +81,10 @@ index d0f7b749b9a6..4e572ce73a2f 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 081e5c0a3ddf..e552c8bed5fe 100644 +index 0b03176f07aa..c526db8b69d2 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -480,6 +480,7 @@ struct pci_dev { +@@ -486,6 +486,7 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ @@ -93,5 +93,5 @@ index 081e5c0a3ddf..e552c8bed5fe 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0012-surface-gpe.patch b/patches/6.15/0012-surface-gpe.patch index 6565ca95fe..e17f7e53eb 100644 --- a/patches/6.15/0012-surface-gpe.patch +++ b/patches/6.15/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From d84d983b64ea9a0b22b3880d9427a00730c4c540 Mon Sep 17 00:00:00 2001 +From 55f4befd22883ebdb8a2ace5ae266ccf0a4a138f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index b359413903b1..b4496db79f39 100644 .ident = "Surface Book 1", .matches = { -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0013-cameras.patch b/patches/6.15/0013-cameras.patch index 75479d60b0..1177da1c17 100644 --- a/patches/6.15/0013-cameras.patch +++ b/patches/6.15/0013-cameras.patch @@ -1,4 +1,4 @@ -From d7a8ba1f35bd8778f60f9b8fc921178477a483eb Mon Sep 17 00:00:00 2001 +From f4a6dd6dc6edd292095b0f01051d6e90e520ecca Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index fb1fe9f3b1a3..5be8893b3912 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.50.1 +2.51.0 -From c37e3f6ba4be4721a325656cc97b64b77301025f Mon Sep 17 00:00:00 2001 +From 3eea25192fd66c8ced9694ec68757fb1d09c348a Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index a5e75c91734c..e5d707a10905 100644 +index 4dc0c206d8a1..2132278e627e 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -132,7 +132,7 @@ index a5e75c91734c..e5d707a10905 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -1944,6 +1953,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1957,6 +1966,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index a5e75c91734c..e5d707a10905 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2240,6 +2252,9 @@ static int __init init_dmars(void) +@@ -2253,6 +2265,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index a5e75c91734c..e5d707a10905 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4463,6 +4478,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4479,6 +4494,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index a5e75c91734c..e5d707a10905 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4513,6 +4540,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4529,6 +4556,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index a5e75c91734c..e5d707a10905 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.50.1 +2.51.0 -From 61c89ac5ab41e85c00827af3ba30a5ba2067cf7b Mon Sep 17 00:00:00 2001 +From 4b200899714ce804e4c7807218b25efdb069b655 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 81ac4c691963..f453c9043042 100644 return 0; -- -2.50.1 +2.51.0 -From c3c8a3be2c044189765a265ca6ec85b277aeb127 Mon Sep 17 00:00:00 2001 +From b387e3ac7ddd78a29cc58f90935ada6a0bc93e35 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -258,9 +258,9 @@ index 3226888d77e9..3bfe45b764f7 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.50.1 +2.51.0 -From d42b6cb9654d528bc018218d0235fd3781f843a8 Mon Sep 17 00:00:00 2001 +From 160e73996b82ec3ec046359591e04b4b5a6166fc Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -309,9 +309,9 @@ index cb153ce42c45..f11b499e14bb 100644 if (ret < 0) goto out_cleanup; -- -2.50.1 +2.51.0 -From 38002558e074b628d78cc3fee9a27e063d2f98c7 Mon Sep 17 00:00:00 2001 +From 253c3518c9c6911bd24c6cd8af6bd17411fe9290 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -350,9 +350,9 @@ index f453c9043042..b8ad6b413e8b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.50.1 +2.51.0 -From a3b8fbb54adcb82e9d3c60032d8b8818ecbb08d3 Mon Sep 17 00:00:00 2001 +From 6d968e793dfceab0ccd3364da326df65864477c4 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -391,9 +391,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.50.1 +2.51.0 -From 6ab1105d05bd2c4cd64744390d27a229078d45b2 Mon Sep 17 00:00:00 2001 +From 54fb950d16116f19179a7c95a6f69e9676e9f287 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -642,9 +642,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.50.1 +2.51.0 -From 5bc63841857aa754c76d7bf5834c0e77262ebdab Mon Sep 17 00:00:00 2001 +From 7f206da7835dcaa506e4bac6c6b8d59f4e9a2f26 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -674,5 +674,5 @@ index 032fbcb981f2..e03a1d8cdcb4 100644 cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); fsleep(100); -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0014-amd-gpio.patch b/patches/6.15/0014-amd-gpio.patch index e313afc828..dc2ac60054 100644 --- a/patches/6.15/0014-amd-gpio.patch +++ b/patches/6.15/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From cfbefb2a747f6b74f344010e5f19127905665cb4 Mon Sep 17 00:00:00 2001 +From 7f3827b691851b75ad0a6aef78f78ac2085fe586 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 9fa321a95eb3..8914a922be2b 100644 mp_config_acpi_legacy_irqs(); -- -2.50.1 +2.51.0 -From 2b6f6c6427e1ff8d84380395bb89490d3ec2b795 Mon Sep 17 00:00:00 2001 +From 2de4d8dda47df161ae25722bad104bf28dae255a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 8914a922be2b..c43d0a553867 100644 }; -- -2.50.1 +2.51.0 diff --git a/patches/6.15/0015-rtc.patch b/patches/6.15/0015-rtc.patch index 3752a5dbcd..0cfc2685c3 100644 --- a/patches/6.15/0015-rtc.patch +++ b/patches/6.15/0015-rtc.patch @@ -1,4 +1,4 @@ -From 4aa3d0d5e53d533c198d2eb0568ec294889856ca Mon Sep 17 00:00:00 2001 +From 122a63dc573c878b58e0b0728d13db666753f5cf Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 825c2a8acea4..74612088ac5f 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.50.1 +2.51.0 From 15eba6143c41189b2251c39b3072e2f31b18f0de Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Sep 2025 13:31:55 +0200 Subject: [PATCH 120/236] Update v6.16 patches Changes: - Rebase onto v6.16.9 Links: - kernel: https://github.com/linux-surface/kernel/commit/bc0020cb77950499ba8166abe4e0b08ebd1aeb21 --- patches/6.16/0001-secureboot.patch | 16 +++---- patches/6.16/0002-surface3.patch | 8 ++-- patches/6.16/0003-mwifiex.patch | 16 +++---- patches/6.16/0004-ath10k.patch | 6 +-- patches/6.16/0005-ipts.patch | 24 +++++----- patches/6.16/0006-ithc.patch | 8 ++-- patches/6.16/0007-surface-sam.patch | 8 ++-- patches/6.16/0008-surface-sam-over-hid.patch | 14 +++--- patches/6.16/0009-surface-button.patch | 8 ++-- patches/6.16/0010-surface-typecover.patch | 42 ++++++++--------- patches/6.16/0011-surface-shutdown.patch | 8 ++-- patches/6.16/0012-surface-gpe.patch | 4 +- patches/6.16/0013-cameras.patch | 48 ++++++++++---------- patches/6.16/0014-amd-gpio.patch | 8 ++-- patches/6.16/0015-rtc.patch | 4 +- 15 files changed, 111 insertions(+), 111 deletions(-) diff --git a/patches/6.16/0001-secureboot.patch b/patches/6.16/0001-secureboot.patch index c8de95e127..66c06f1908 100644 --- a/patches/6.16/0001-secureboot.patch +++ b/patches/6.16/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 31b55a34f02fd0f89b035b5869ae17b9030373b0 Mon Sep 17 00:00:00 2001 +From e87eeb0fa251c56d9966ad1e59b261ee0b14a566 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index e1f4fd5bc8ee..64f8dc548045 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.50.1 +2.51.0 -From 36688672f7609811066f521600e9e39230038f7e Mon Sep 17 00:00:00 2001 +From d697f8d42f404ba2615c63a36f3ce73931dcf2ea Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index f6d317e1674d..21351e253cb2 100644 +index 089e1a395178..9111ec4feff4 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3243,6 +3243,11 @@ @@ -69,7 +69,7 @@ index f6d317e1674d..21351e253cb2 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 9216e3b91d3b..ff774a584022 100644 +index c8022a477d3a..d6feab73fad5 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -38,6 +38,7 @@ @@ -89,7 +89,7 @@ index 9216e3b91d3b..ff774a584022 100644 !secretmem_active() && !cxl_mem_active(); } -@@ -1456,6 +1457,12 @@ static int __init nohibernate_setup(char *str) +@@ -1457,6 +1458,12 @@ static int __init nohibernate_setup(char *str) return 1; } @@ -102,11 +102,11 @@ index 9216e3b91d3b..ff774a584022 100644 static const char * const comp_alg_enabled[] = { #if IS_ENABLED(CONFIG_CRYPTO_LZO) COMPRESSION_ALGO_LZO, -@@ -1513,3 +1520,4 @@ __setup("hibernate=", hibernate_setup); +@@ -1514,3 +1521,4 @@ __setup("hibernate=", hibernate_setup); __setup("resumewait", resumewait_setup); __setup("resumedelay=", resumedelay_setup); __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0002-surface3.patch b/patches/6.16/0002-surface3.patch index cb761a6b27..082cf31f61 100644 --- a/patches/6.16/0002-surface3.patch +++ b/patches/6.16/0002-surface3.patch @@ -1,4 +1,4 @@ -From 0a5a737452cff78ac984b95fad50dc1da97da7f6 Mon Sep 17 00:00:00 2001 +From 594f39a9ca0f976ec3ab30fa6852ad4c2b4831a0 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,9 +97,9 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.50.1 +2.51.0 -From f1f0eecb0b055bc8cc328695dd47103f482f3872 Mon Sep 17 00:00:00 2001 +From 48541ded57baafc01b4a738a056c3ccec25c8df1 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -230,5 +230,5 @@ index 6074b7730e86..6aa3e1d6f160 100644 } -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0003-mwifiex.patch b/patches/6.16/0003-mwifiex.patch index 9f7fc19a19..99b935a418 100644 --- a/patches/6.16/0003-mwifiex.patch +++ b/patches/6.16/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 41b114b1636bdd55c952e21d752c9d020e44c952 Mon Sep 17 00:00:00 2001 +From ac77045658a4d9764b9a6395e7b193ed14414ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.50.1 +2.51.0 -From 586fd6566d18606b857c823f271d74172c1cea40 Mon Sep 17 00:00:00 2001 +From f57cfe5a93d9d0bd3024367ffa9c99812feab8e0 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.50.1 +2.51.0 -From 68e3fb977dd163d6344ea5cf1a5248d33353976c Mon Sep 17 00:00:00 2001 +From 4c7809f1af22d2502869a90f8958f89ef7bc0a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index e8977fff4212..d16c47e6df0f 100644 +index 9efdd111baf5..6c68639f9f5d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index e8977fff4212..d16c47e6df0f 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4076,6 +4078,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4079,6 +4081,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index e8977fff4212..d16c47e6df0f 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0004-ath10k.patch b/patches/6.16/0004-ath10k.patch index fa08939990..8e83e1928f 100644 --- a/patches/6.16/0004-ath10k.patch +++ b/patches/6.16/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 94aced4a2343f676d6d6909af57fdcc867b04a46 Mon Sep 17 00:00:00 2001 +From 61461ed065cb724b5fc971cb0c5272ef3313a42f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index fe3a8f4a1cc1..06f7bba95bc3 100644 +index 8b659678856d..5ed699691b39 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -40,6 +40,9 @@ static bool fw_diag_log; @@ -116,5 +116,5 @@ index fe3a8f4a1cc1..06f7bba95bc3 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0005-ipts.patch b/patches/6.16/0005-ipts.patch index 8500d22082..0e12d537e0 100644 --- a/patches/6.16/0005-ipts.patch +++ b/patches/6.16/0005-ipts.patch @@ -1,4 +1,4 @@ -From ff5ea37cd3d84e04e2563a61004ddc81c13d20e8 Mon Sep 17 00:00:00 2001 +From 0ada79877cefaf982ffd379465e225042a283208 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -35,9 +35,9 @@ index 3f9c60b579ae..853a67753333 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.50.1 +2.51.0 -From 8571d8878e37c95486ba4d2b5c68c226372c57a7 Mon Sep 17 00:00:00 2001 +From 3153c571ead4689a56c8b6cf35a3030e6cff7683 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index c0be0b64e4c7..04bf55541281 100644 +index 3dd4d73fcb5d..98def863f736 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -76,7 +76,7 @@ index c0be0b64e4c7..04bf55541281 100644 #define IOAPIC_RANGE_START (0xfee00000) #define IOAPIC_RANGE_END (0xfeefffff) #define IOVA_START_ADDR (0x1000) -@@ -207,12 +212,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); +@@ -209,12 +214,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); int intel_iommu_enabled = 0; EXPORT_SYMBOL_GPL(intel_iommu_enabled); @@ -91,7 +91,7 @@ index c0be0b64e4c7..04bf55541281 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -1885,6 +1892,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1897,6 +1904,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index c0be0b64e4c7..04bf55541281 100644 } return 0; -@@ -2175,6 +2185,9 @@ static int __init init_dmars(void) +@@ -2187,6 +2197,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index c0be0b64e4c7..04bf55541281 100644 check_tylersburg_isoch(); /* -@@ -4398,6 +4411,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4516,6 +4529,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index c0be0b64e4c7..04bf55541281 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4436,6 +4461,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4554,6 +4579,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index c0be0b64e4c7..04bf55541281 100644 { if (risky_device(dev)) -- -2.50.1 +2.51.0 -From 03cbd44a2e522b8c77f560810cb992e1d2e0416a Mon Sep 17 00:00:00 2001 +From 7929eb6116ecdfacbf0bd288ae8f57a03f00b81a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3239,5 +3239,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0006-ithc.patch b/patches/6.16/0006-ithc.patch index 8320c2b2f4..2a49c75fe0 100644 --- a/patches/6.16/0006-ithc.patch +++ b/patches/6.16/0006-ithc.patch @@ -1,4 +1,4 @@ -From c0b6befe8895c4e40e25568027171fbe5e03fb95 Mon Sep 17 00:00:00 2001 +From 020ac25e7bf02edab684906a300a8624e2353b0d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index cf7b6882ec75..55ab16865774 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.50.1 +2.51.0 -From 67ffc2306c491a00557b995631819f5924a2bc7d Mon Sep 17 00:00:00 2001 +From f698eb55ef20a37e5724d7e8f5cb609d12fcabcc Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -2776,5 +2776,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0007-surface-sam.patch b/patches/6.16/0007-surface-sam.patch index 73633bce42..e4534b697e 100644 --- a/patches/6.16/0007-surface-sam.patch +++ b/patches/6.16/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 171bc5acbbdaa975f8695af30f208d7facb21eef Mon Sep 17 00:00:00 2001 +From b83775761995a645f0c958d518ae0e9dc2c40cb7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -179,9 +179,9 @@ index 000000000000..f6c17c4e98d5 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.50.1 +2.51.0 -From 4ad519e396f03823a1703c67626c8aee216738c1 Mon Sep 17 00:00:00 2001 +From d8f161cde861f572e191a8f7baa59d8e55051799 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -207,5 +207,5 @@ index a594d5fcfcfd..07b03aa4fa7f 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0008-surface-sam-over-hid.patch b/patches/6.16/0008-surface-sam-over-hid.patch index 52c1e51764..5df78a93da 100644 --- a/patches/6.16/0008-surface-sam-over-hid.patch +++ b/patches/6.16/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 08d1c56b91078576f586b8ee8486fe923edd0ef6 Mon Sep 17 00:00:00 2001 +From e65ba8e7b543f1a0af66062d05d9d98c4602a8ad Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,10 +55,10 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index d2499f302b50..77ce5ec3dd9e 100644 +index f43067f6797e..1761ca30e17a 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c -@@ -661,6 +661,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, +@@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, return (ret == 1) ? 0 : -EIO; } @@ -86,7 +86,7 @@ index d2499f302b50..77ce5ec3dd9e 100644 static acpi_status i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, -@@ -762,6 +783,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, +@@ -763,6 +784,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, } break; @@ -107,9 +107,9 @@ index d2499f302b50..77ce5ec3dd9e 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.50.1 +2.51.0 -From ac87ea167ba39b5a64b4b5ddd19995f1b17bcd96 Mon Sep 17 00:00:00 2001 +From c9c5d92d081d485de80aad30f535768848263247 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0009-surface-button.patch b/patches/6.16/0009-surface-button.patch index 96ee92a90e..3dbb165f9a 100644 --- a/patches/6.16/0009-surface-button.patch +++ b/patches/6.16/0009-surface-button.patch @@ -1,4 +1,4 @@ -From fa6b68c8fc4730eae6ab0da7e556500d5ee0d7bd Mon Sep 17 00:00:00 2001 +From 13a6e5683a378d75df86470a039bb41d9d98e7eb Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index b8cad415c62c..43b5d56383e3 100644 /* -- -2.50.1 +2.51.0 -From b8a8524062bafde8551aa43b7e7cec037be6d775 Mon Sep 17 00:00:00 2001 +From de2da3530b7fda779b5b5eb86b1f2d35087828fd Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0010-surface-typecover.patch b/patches/6.16/0010-surface-typecover.patch index c078b6f0aa..0d292fa0d0 100644 --- a/patches/6.16/0010-surface-typecover.patch +++ b/patches/6.16/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 7cb8f7223f9deffff0c8f56d4c6e07e58aff3e50 Mon Sep 17 00:00:00 2001 +From 0c9d7910c676745bcbac6439f0fd0697ec0dd327 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 0cf94c7a2c9c..115d2628cdb6 100644 +index d6daad39491b..2e50dd89b800 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index 0cf94c7a2c9c..115d2628cdb6 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.50.1 +2.51.0 -From 8d42e72cdbdff8d754caecc3e1e51b9f5d6b032f Mon Sep 17 00:00:00 2001 +From 096340b6ad9ccc772d7f1be6ea455f48ee5f72a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index a1c54ffe02b4..3acf2719cea4 100644 +index 4c22bd2ba170..e231393da178 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -147,7 +147,7 @@ index a1c54ffe02b4..3acf2719cea4 100644 { } }; -@@ -1759,6 +1779,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1767,6 +1787,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index a1c54ffe02b4..3acf2719cea4 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1782,6 +1865,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1790,6 +1873,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index a1c54ffe02b4..3acf2719cea4 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1820,8 +1906,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1828,8 +1914,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index a1c54ffe02b4..3acf2719cea4 100644 if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1830,8 +1918,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1838,8 +1926,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index a1c54ffe02b4..3acf2719cea4 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1881,6 +1971,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1889,6 +1979,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index a1c54ffe02b4..3acf2719cea4 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2320,6 +2411,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2328,6 +2419,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -272,9 +272,9 @@ index a1c54ffe02b4..3acf2719cea4 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.50.1 +2.51.0 -From 27fe08e59a1e4e1c16fe3724bc43be188c85ba6e Mon Sep 17 00:00:00 2001 +From dd133146d7777b2793f31952b45dbcc9fd89e900 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 3acf2719cea4..a359afb687af 100644 +index e231393da178..d9b80e1dd3c6 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); @@ -413,7 +413,7 @@ index 3acf2719cea4..a359afb687af 100644 return 0; } -@@ -1646,6 +1692,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1654,6 +1700,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index 3acf2719cea4..a359afb687af 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1694,6 +1776,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1702,6 +1784,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 3acf2719cea4..a359afb687af 100644 default: suffix = "UNKNOWN"; break; -@@ -1779,30 +1868,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1787,30 +1876,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 3acf2719cea4..a359afb687af 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1811,8 +1876,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1819,8 +1884,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 3acf2719cea4..a359afb687af 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -1949,13 +2015,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -1957,13 +2023,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 3acf2719cea4..a359afb687af 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1964,12 +2041,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -1972,12 +2049,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); @@ -571,5 +571,5 @@ index 3acf2719cea4..a359afb687af 100644 unregister_pm_notifier(&td->pm_notifier); timer_delete_sync(&td->release_timer); -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0011-surface-shutdown.patch b/patches/6.16/0011-surface-shutdown.patch index fda7911d93..39853cfbc6 100644 --- a/patches/6.16/0011-surface-shutdown.patch +++ b/patches/6.16/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 4e3a09a8d12d4e20529e1f2d4d94552478b6f05b Mon Sep 17 00:00:00 2001 +From 9653abf64529b1ac674213c039d3d1be04dd853d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -81,10 +81,10 @@ index db6e142b082d..c9bb44f2b37e 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 05e68f35f392..cc50c771481e 100644 +index d56d0dd80afb..4bd88eda9c7f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -478,6 +478,7 @@ struct pci_dev { +@@ -484,6 +484,7 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ @@ -93,5 +93,5 @@ index 05e68f35f392..cc50c771481e 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0012-surface-gpe.patch b/patches/6.16/0012-surface-gpe.patch index e5fe78880a..155224fa40 100644 --- a/patches/6.16/0012-surface-gpe.patch +++ b/patches/6.16/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 48ee98b4ea3d491f1dde163053200cf0bc7eea9e Mon Sep 17 00:00:00 2001 +From 81c20c9fb321319c93fa3d89de5842c9916309df Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index b359413903b1..b4496db79f39 100644 .ident = "Surface Book 1", .matches = { -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0013-cameras.patch b/patches/6.16/0013-cameras.patch index 179c553245..512f731b98 100644 --- a/patches/6.16/0013-cameras.patch +++ b/patches/6.16/0013-cameras.patch @@ -1,4 +1,4 @@ -From a3228469f0d8004a18e50bde7daaff298e0211a6 Mon Sep 17 00:00:00 2001 +From 6d3b7898c2d4ca1e93bca6467377087e59b4fe6e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index fb1fe9f3b1a3..5be8893b3912 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.50.1 +2.51.0 -From b6739021e214bf8a47c1774e9d348712a19117a3 Mon Sep 17 00:00:00 2001 +From 963e4c165afc61c5faba46f8ca20c1d0b2932db7 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 04bf55541281..5a8cac788e5a 100644 +index 98def863f736..15af4773df7e 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -117,7 +117,7 @@ index 04bf55541281..5a8cac788e5a 100644 #define IOAPIC_RANGE_START (0xfee00000) #define IOAPIC_RANGE_END (0xfeefffff) #define IOVA_START_ADDR (0x1000) -@@ -213,12 +220,14 @@ int intel_iommu_enabled = 0; +@@ -215,12 +222,14 @@ int intel_iommu_enabled = 0; EXPORT_SYMBOL_GPL(intel_iommu_enabled); static int dmar_map_ipts = 1; @@ -132,7 +132,7 @@ index 04bf55541281..5a8cac788e5a 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -1893,6 +1902,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1905,6 +1914,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index 04bf55541281..5a8cac788e5a 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2185,6 +2197,9 @@ static int __init init_dmars(void) +@@ -2197,6 +2209,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index 04bf55541281..5a8cac788e5a 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4411,6 +4426,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4529,6 +4544,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index 04bf55541281..5a8cac788e5a 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4461,6 +4488,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4579,6 +4606,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index 04bf55541281..5a8cac788e5a 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.50.1 +2.51.0 -From d97d4bdb6b030eca0e4f1b9e6d36333cd115b6c9 Mon Sep 17 00:00:00 2001 +From a61ad0677bd36ec052487ab4cef6101d8138d6f1 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 0133405697dc..9e0763bdc758 100644 return 0; -- -2.50.1 +2.51.0 -From ac22813bbf6f8879a522658ff81e0eccce9d75c4 Mon Sep 17 00:00:00 2001 +From 39e4ca443f7436678999b2e4c63fe6c7c79b821a Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -258,9 +258,9 @@ index 3226888d77e9..3bfe45b764f7 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.50.1 +2.51.0 -From 0b628eac9ac467c74574b290cd8037ca6b1f45b4 Mon Sep 17 00:00:00 2001 +From 67898bb4c736f5846c66fd7737154cdc0ba5e1cd Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -309,9 +309,9 @@ index cb153ce42c45..f11b499e14bb 100644 if (ret < 0) goto out_cleanup; -- -2.50.1 +2.51.0 -From e013334172ad4602e22121ee39d1b7f20dbbcdbd Mon Sep 17 00:00:00 2001 +From be89734907a8d9bc31e1ecb96680d7d1bb94150d Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -350,9 +350,9 @@ index 9e0763bdc758..0976b267972b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.50.1 +2.51.0 -From a6cd8999b346837ae7c30e4ea252968ac040b46a Mon Sep 17 00:00:00 2001 +From acf6a36fee44848bea5ef5ab5394a42f37c5b9bf Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -391,9 +391,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.50.1 +2.51.0 -From 1c74a4a3d26452bdfb6d56afc2c528e48239c8c8 Mon Sep 17 00:00:00 2001 +From 51508796651e42174d2a1105159d66fa4e3ad809 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -642,9 +642,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.50.1 +2.51.0 -From 24642c6d23f656ba43bc0b858f04731b5eb27819 Mon Sep 17 00:00:00 2001 +From dae5c7687ff0f6becfb72b4144e54f7022e54c11 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -674,5 +674,5 @@ index 032fbcb981f2..e03a1d8cdcb4 100644 cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); fsleep(100); -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0014-amd-gpio.patch b/patches/6.16/0014-amd-gpio.patch index 3d91e4afb2..7ed30e117c 100644 --- a/patches/6.16/0014-amd-gpio.patch +++ b/patches/6.16/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 3e91eba1c6da22e8fdd0fe6a7a59895c2210ebe3 Mon Sep 17 00:00:00 2001 +From 05505e5575eb38c3dff121869c72c8c224063f9c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 9fa321a95eb3..8914a922be2b 100644 mp_config_acpi_legacy_irqs(); -- -2.50.1 +2.51.0 -From 6a2df6666086e15b15661dca7782b02689ccdd34 Mon Sep 17 00:00:00 2001 +From 6df4d2ebe1e08d1907af8c90bb152843c465b3d9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 8914a922be2b..c43d0a553867 100644 }; -- -2.50.1 +2.51.0 diff --git a/patches/6.16/0015-rtc.patch b/patches/6.16/0015-rtc.patch index 144144b21a..e9d9916b69 100644 --- a/patches/6.16/0015-rtc.patch +++ b/patches/6.16/0015-rtc.patch @@ -1,4 +1,4 @@ -From 6a7a9e768afa2d659be5457a85788db87008a7b9 Mon Sep 17 00:00:00 2001 +From bc0020cb77950499ba8166abe4e0b08ebd1aeb21 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 825c2a8acea4..74612088ac5f 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.50.1 +2.51.0 From a34755500efd6acf9e809c833c1671b968d947b5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Sep 2025 14:07:41 +0200 Subject: [PATCH 121/236] Add patches for 6.17 Derived from latest 6.16 patches Links: - kernel: https://github.com/linux-surface/kernel/commit/1069b63e699910262e7cbc208701c9184075244d - tree-devel: https://github.com/linux-surface/kernel/tree/v6.17-surface-devel - tree-patches: https://github.com/linux-surface/kernel/tree/v6.17-surface --- patches/6.17/0001-secureboot.patch | 112 + patches/6.17/0002-surface3.patch | 234 ++ patches/6.17/0003-mwifiex.patch | 400 +++ patches/6.17/0004-ath10k.patch | 120 + patches/6.17/0005-ipts.patch | 3243 ++++++++++++++++++ patches/6.17/0006-ithc.patch | 2780 +++++++++++++++ patches/6.17/0007-surface-sam.patch | 211 ++ patches/6.17/0008-surface-sam-over-hid.patch | 308 ++ patches/6.17/0009-surface-button.patch | 149 + patches/6.17/0010-surface-typecover.patch | 575 ++++ patches/6.17/0011-surface-shutdown.patch | 97 + patches/6.17/0012-surface-gpe.patch | 51 + patches/6.17/0013-cameras.patch | 678 ++++ patches/6.17/0014-amd-gpio.patch | 109 + patches/6.17/0015-rtc.patch | 110 + 15 files changed, 9177 insertions(+) create mode 100644 patches/6.17/0001-secureboot.patch create mode 100644 patches/6.17/0002-surface3.patch create mode 100644 patches/6.17/0003-mwifiex.patch create mode 100644 patches/6.17/0004-ath10k.patch create mode 100644 patches/6.17/0005-ipts.patch create mode 100644 patches/6.17/0006-ithc.patch create mode 100644 patches/6.17/0007-surface-sam.patch create mode 100644 patches/6.17/0008-surface-sam-over-hid.patch create mode 100644 patches/6.17/0009-surface-button.patch create mode 100644 patches/6.17/0010-surface-typecover.patch create mode 100644 patches/6.17/0011-surface-shutdown.patch create mode 100644 patches/6.17/0012-surface-gpe.patch create mode 100644 patches/6.17/0013-cameras.patch create mode 100644 patches/6.17/0014-amd-gpio.patch create mode 100644 patches/6.17/0015-rtc.patch diff --git a/patches/6.17/0001-secureboot.patch b/patches/6.17/0001-secureboot.patch new file mode 100644 index 0000000000..741a06a348 --- /dev/null +++ b/patches/6.17/0001-secureboot.patch @@ -0,0 +1,112 @@ +From 79b500c983f2399294fca8bcd153b50a955d0aa1 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index 9bea5a1e2c52..25848f886ad6 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLLCHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.51.0 + +From 8447597cf4fbb341325e07ef2a75d92393a15f29 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 5a7a83c411e9..f67ddee8c4b4 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3298,6 +3298,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 2f66ab453823..bb9e800b3374 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -38,6 +38,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -98,7 +99,7 @@ bool hibernation_in_progress(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1483,6 +1484,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1540,3 +1547,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.51.0 + diff --git a/patches/6.17/0002-surface3.patch b/patches/6.17/0002-surface3.patch new file mode 100644 index 0000000000..0850ad8df4 --- /dev/null +++ b/patches/6.17/0002-surface3.patch @@ -0,0 +1,234 @@ +From 47044a281bffc78cc1f3bb9859e098e2678c55ff Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3 +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index 6c8fb7a4dde4..22797a53f4d8 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 29a403526cd9..986f32132c3d 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3792,6 +3792,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.51.0 + +From f4ac64d3cfabf7aef3ba9465df2c4237853a461b Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Fri, 6 Dec 2019 23:10:30 +0900 +Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by + default + +On Arch Linux kernel at least after 4.19, touch input is broken after suspend +(s2idle). + + kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + +On recent stable Arch Linux kernel (at least after 5.1), touch input will +crash after the first touch. + + kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue + +I found on an affected system (Arch Linux kernel, etc.), the touchscreen +driver uses DMA mode by default. Then, we found some kernels with different +kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel +chromeos-4.19 [2]) will use PIO mode by default and no such issues there. + +So, this commit disables DMA mode on the touchscreen driver side as a quick +workaround to avoid touch input crash. +We may need to properly set up DMA mode to use the touchscreen driver with +DMA mode. + +You can still switch DMA/PIO mode if you want: + + switch to DMA mode (maybe broken) + echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma + back to PIO mode + echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma + +Link to issue: https://github.com/jakeday/linux-surface/issues/596 + +References: +[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config +[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 + +Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. +This commit made the driver use PIO by default and no touch input crash. +Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default +even without this commit. After this commit, it still uses PIO and confirmed +no functional changes regarding touch input. + +More details: + We can confirm which mode the touchscreen driver uses; first, enable + debug output: + + echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + + Then, try to make a touch input and see dmesg log + + (On Arch Linux kernel, uses DMA) + kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA + kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 + c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + + (On the kernels I referenced above, uses PIO) + kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO + kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 + 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Note (2025-03-08): This patch was originally dropped due to the +comments in [3]. However, according to the commments in [4] it is still +required. + +[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a +[4]: https://github.com/linux-surface/linux-surface/issues/1184 + +Patchset: surface3 +--- + drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c +index 6074b7730e86..6aa3e1d6f160 100644 +--- a/drivers/input/touchscreen/surface3_spi.c ++++ b/drivers/input/touchscreen/surface3_spi.c +@@ -25,6 +25,12 @@ + #define SURFACE3_REPORT_TOUCH 0xd2 + #define SURFACE3_REPORT_PEN 0x16 + ++bool use_dma = false; ++module_param(use_dma, bool, 0644); ++MODULE_PARM_DESC(use_dma, ++ "Disable DMA mode if you encounter touch input crash. " ++ "(default: false, disabled to avoid crash)"); ++ + struct surface3_ts_data { + struct spi_device *spi; + struct gpio_desc *gpiod_rst[2]; +@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) + return 0; + } + ++static bool surface3_spi_can_dma(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) ++{ ++ return use_dma; ++} ++ + static int surface3_spi_probe(struct spi_device *spi) + { + struct surface3_ts_data *data; +@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) + if (error) + return error; + ++ /* ++ * Set up DMA ++ * ++ * TODO: Currently, touch input with DMA seems to be broken. ++ * On 4.19 LTS, touch input will crash after suspend. ++ * On recent stable kernel (at least after 5.1), touch input will crash after ++ * the first touch. No problem with PIO on those kernels. ++ * Maybe we need to configure DMA here. ++ * ++ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 ++ */ ++ spi->controller->can_dma = surface3_spi_can_dma; ++ + return 0; + } + +-- +2.51.0 + diff --git a/patches/6.17/0003-mwifiex.patch b/patches/6.17/0003-mwifiex.patch new file mode 100644 index 0000000000..0cf2a91b38 --- /dev/null +++ b/patches/6.17/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From c8cd7b083a416fd1e271673a99b9803ad81fec99 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index a760de191fce..db9b203226a8 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.51.0 + +From 32b04d17da87e550fa7dfa3c8900bf0d54e26285 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index db9b203226a8..ffd0c1fe9223 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.51.0 + +From f01145c4f95b75eaf6610281143cbce63ca5d98e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 8085fabadde8..315cb98b324e 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -471,6 +472,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -4129,6 +4131,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.51.0 + diff --git a/patches/6.17/0004-ath10k.patch b/patches/6.17/0004-ath10k.patch new file mode 100644 index 0000000000..4952aa84ec --- /dev/null +++ b/patches/6.17/0004-ath10k.patch @@ -0,0 +1,120 @@ +From 0f6d06101eefd596f349162daee7203a6d5ad61d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index 6f78f1752cd6..8f7be9cf8a9d 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -42,6 +42,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -54,6 +57,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -63,6 +69,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -933,6 +942,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -947,6 +992,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.51.0 + diff --git a/patches/6.17/0005-ipts.patch b/patches/6.17/0005-ipts.patch new file mode 100644 index 0000000000..2ec5e93ba4 --- /dev/null +++ b/patches/6.17/0005-ipts.patch @@ -0,0 +1,3243 @@ +From c4e655d712504f5d756f45541f2fdcb3707cd6c1 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index bc40b940ae21..45fbd856d416 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 3f9c60b579ae..853a67753333 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.51.0 + +From 6d3a8407644210b599bd5cd7bf10942ad7204fcc Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index dff2d895b8ab..dc95cb3375fe 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -39,6 +39,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -209,12 +214,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -1879,6 +1886,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2169,6 +2179,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4515,6 +4528,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4553,6 +4578,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.51.0 + +From c3091f09b9deb8831412f84c13462ab04b86622e Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index b934523593d9..b2cc5db65f5b 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1428,6 +1428,8 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 10ae5dedbd84..7ba7d26391e9 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -175,3 +175,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.51.0 + diff --git a/patches/6.17/0006-ithc.patch b/patches/6.17/0006-ithc.patch new file mode 100644 index 0000000000..89b9a6f22a --- /dev/null +++ b/patches/6.17/0006-ithc.patch @@ -0,0 +1,2780 @@ +From 48882c74dd11fe6ce6927c50d694d7dc3cdfc46f Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 4f9b01dc91e8..e4d73e45473c 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.51.0 + +From c49156368b0af34f99dddff87eec0c70a5af7a3e Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 438 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2575 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index b2cc5db65f5b..707983ce6854 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1430,6 +1430,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 7ba7d26391e9..d939da7ac2e8 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -177,3 +177,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..094d878d671b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,438 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) }, ++ // MTL and up are handled by drivers/hid/intel-thc-hid ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ timer_delete_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.51.0 + diff --git a/patches/6.17/0007-surface-sam.patch b/patches/6.17/0007-surface-sam.patch new file mode 100644 index 0000000000..518e852538 --- /dev/null +++ b/patches/6.17/0007-surface-sam.patch @@ -0,0 +1,211 @@ +From 487f40f72255d0ac23f35612c40812869b97f2c1 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 17 Jun 2022 02:14:00 +0200 +Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator + Module + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/rtc/Kconfig | 7 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 drivers/rtc/rtc-surface.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 64f6e9756aff..bf05361f7f13 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1379,6 +1379,13 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_SURFACE ++ tristate "Microsoft Surface Aggregator RTC" ++ depends on SURFACE_AGGREGATOR ++ depends on SURFACE_AGGREGATOR_BUS ++ help ++ TODO ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 789bddfea99d..a6df07332080 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -181,6 +181,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o + obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o + obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o + obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o ++obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o +diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c +new file mode 100644 +index 000000000000..f6c17c4e98d5 +--- /dev/null ++++ b/drivers/rtc/rtc-surface.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * AC driver for 7th-generation Microsoft Surface devices via Surface System ++ * Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2019-2021 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct surface_rtc { ++ struct ssam_device *sdev; ++ struct rtc_device *rtc; ++}; ++ ++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x10, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x0f, ++}); ++ ++static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) ++{ ++ __le32 time_le; ++ int status; ++ ++ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); ++ if (status) ++ return status; ++ ++ *time = le32_to_cpu(time_le); ++ return 0; ++} ++ ++static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) ++{ ++ __le32 time_le = cpu_to_le32(time); ++ ++ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); ++} ++ ++static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ int status; ++ u32 time; ++ ++ status = ssam_rtc_get_unix_time(srtc, &time); ++ if (status) ++ return status; ++ ++ rtc_time64_to_tm(time, tm); ++ return 0; ++} ++ ++static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ time64_t time = rtc_tm_to_time64(tm); ++ ++ return ssam_rtc_set_unix_time(srtc, (u32)time); ++} ++ ++static const struct rtc_class_ops surface_rtc_ops = { ++ .read_time = surface_rtc_read_time, ++ .set_time = surface_rtc_set_time, ++}; ++ ++static int surface_rtc_probe(struct ssam_device *sdev) ++{ ++ struct surface_rtc *srtc; ++ ++ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->sdev = sdev; ++ ++ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); ++ if (IS_ERR(srtc->rtc)) ++ return PTR_ERR(srtc->rtc); ++ ++ srtc->rtc->ops = &surface_rtc_ops; ++ srtc->rtc->range_max = U32_MAX; ++ ++ ssam_device_set_drvdata(sdev, srtc); ++ ++ return devm_rtc_register_device(srtc->rtc); ++} ++ ++static void surface_rtc_remove(struct ssam_device *sdev) ++{ ++ /* Device-managed allocations take care of everything... */ ++} ++ ++static const struct ssam_device_id surface_rtc_match[] = { ++ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, surface_rtc_match); ++ ++static struct ssam_device_driver surface_rtc_driver = { ++ .probe = surface_rtc_probe, ++ .remove = surface_rtc_remove, ++ .match_table = surface_rtc_match, ++ .driver = { ++ .name = "surface_rtc", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(surface_rtc_driver); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + +From 9977281edd9310d64900a4d4c1709823019b9a47 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 20 Apr 2025 01:05:14 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 + (ACPI) + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index a594d5fcfcfd..07b03aa4fa7f 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Laptop 6 */ + { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + ++ /* Surface Laptop 7 */ ++ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.51.0 + diff --git a/patches/6.17/0008-surface-sam-over-hid.patch b/patches/6.17/0008-surface-sam-over-hid.patch new file mode 100644 index 0000000000..56c0f42b65 --- /dev/null +++ b/patches/6.17/0008-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From f8c0ddcb0164e1a1702102ce13bf5e09568d5c0a Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index ed90858a27b7..070c36637811 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -763,6 +784,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.51.0 + +From 7f1e39bb740f65df743017db3196d5029bd3ffa3 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index f775c6ca1ec1..2075e3852053 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + diff --git a/patches/6.17/0009-surface-button.patch b/patches/6.17/0009-surface-button.patch new file mode 100644 index 0000000000..717e196815 --- /dev/null +++ b/patches/6.17/0009-surface-button.patch @@ -0,0 +1,149 @@ +From e510633b5a7258dcc54cf166d7c994dc867fedda Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index b8cad415c62c..43b5d56383e3 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.51.0 + +From 462ebc6ad95ead44113459c7c20d0612e1af5e11 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.51.0 + diff --git a/patches/6.17/0010-surface-typecover.patch b/patches/6.17/0010-surface-typecover.patch new file mode 100644 index 0000000000..b510a6458f --- /dev/null +++ b/patches/6.17/0010-surface-typecover.patch @@ -0,0 +1,575 @@ +From 9b522924acc63d21b9ea6df651c2dcb04f294034 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index f5bc53875330..31fa895d73c4 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.51.0 + +From 5f558fb565ae75a0bebe6ae74c1f699bbe3accae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 22c6314a8843..062c9de23db9 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -35,7 +35,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + /* quirks to control the device */ + #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) +@@ -74,12 +78,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -177,6 +184,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -222,6 +231,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 + #define MT_CLS_APPLE_TOUCHBAR 0x0114 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -418,6 +428,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1809,6 +1829,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1832,6 +1915,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1870,8 +1956,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && + !hid_find_field(hdev, HID_INPUT_REPORT, +@@ -1885,8 +1973,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1936,6 +2026,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2380,6 +2471,11 @@ static const struct hid_device_id mt_devices[] = { + HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.51.0 + +From 4d38f704475f87a6ec40f3b2ba2184da867c5d55 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 062c9de23db9..487364959ab5 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -79,6 +79,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -86,6 +87,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -430,6 +433,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1445,6 +1449,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1472,6 +1479,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1493,6 +1515,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1500,6 +1523,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1509,11 +1545,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1696,6 +1742,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1744,6 +1826,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1829,30 +1918,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1861,8 +1926,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -2004,13 +2070,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -2019,12 +2096,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); +-- +2.51.0 + diff --git a/patches/6.17/0011-surface-shutdown.patch b/patches/6.17/0011-surface-shutdown.patch new file mode 100644 index 0000000000..443b50bdd7 --- /dev/null +++ b/patches/6.17/0011-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 269ce75e30d184b81b8b40bb0c1bee28abe95082 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 63665240ae87..727364643822 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index d97335a40193..89184a0fb679 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6338,3 +6338,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 59876de13860..41d0a274a550 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -484,6 +484,7 @@ struct pci_dev { + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ + unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.51.0 + diff --git a/patches/6.17/0012-surface-gpe.patch b/patches/6.17/0012-surface-gpe.patch new file mode 100644 index 0000000000..1bbc7a494a --- /dev/null +++ b/patches/6.17/0012-surface-gpe.patch @@ -0,0 +1,51 @@ +From 07f651aa185f63d3dfb917e0083ba1b0e28157c0 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index b359413903b1..b4496db79f39 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.51.0 + diff --git a/patches/6.17/0013-cameras.patch b/patches/6.17/0013-cameras.patch new file mode 100644 index 0000000000..3eede56de2 --- /dev/null +++ b/patches/6.17/0013-cameras.patch @@ -0,0 +1,678 @@ +From 365e0d66f4e0f3681795b63db37ebf14f8e2fdf2 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index fb1fe9f3b1a3..5be8893b3912 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2197,6 +2197,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.51.0 + +From 90cb7694c399c63d5c6c44aba0ee1cb048c6355d Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index dc95cb3375fe..8c900fce80d1 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -44,6 +44,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -215,12 +222,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -1887,6 +1896,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2179,6 +2191,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4528,6 +4543,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4578,6 +4605,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.51.0 + +From ad0067a390921345f7c43779b102f43f3b587f4c Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 0133405697dc..9e0763bdc758 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.51.0 + +From e80f10566f351ea0de98d606a6bbc8c8089a7712 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 31a42d81e970..0d5a8fd86e67 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1579,7 +1579,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.51.0 + +From c7942343d69b7a0dd2868a27ddda3c49b528b784 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index cb153ce42c45..f11b499e14bb 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.51.0 + +From 2a087a81397c2ac9a79a7861e553a40e69eb2aae Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 9e0763bdc758..0976b267972b 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.51.0 + +From 0258799a71d332c75235d50e2ca799863d803508 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.51.0 + +From fd36497dcf8f79d5e5c9dd8b4088d3fb694ee799 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 6e3dce7e35a4..5b6ba103867c 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -1002,6 +1002,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 9a0333ec1a86..4e1ca8fc9b41 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_UPBOARD) += leds-upboard.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.51.0 + +From 4c7a0198b0d3e3e8f074df6cc7841452dd35cd68 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index 032fbcb981f2..e03a1d8cdcb4 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -87,6 +87,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); + fsleep(100); +-- +2.51.0 + diff --git a/patches/6.17/0014-amd-gpio.patch b/patches/6.17/0014-amd-gpio.patch new file mode 100644 index 0000000000..8ccb4c1988 --- /dev/null +++ b/patches/6.17/0014-amd-gpio.patch @@ -0,0 +1,109 @@ +From c8e851f02c44501c75d205fb97dfb3601342cca1 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 9fa321a95eb3..8914a922be2b 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1171,6 +1172,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1227,6 +1239,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.51.0 + +From fd6d2bcfe7ffea0f62054271788b5482818e13ec Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 8914a922be2b..c43d0a553867 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.51.0 + diff --git a/patches/6.17/0015-rtc.patch b/patches/6.17/0015-rtc.patch new file mode 100644 index 0000000000..fa783e1b42 --- /dev/null +++ b/patches/6.17/0015-rtc.patch @@ -0,0 +1,110 @@ +From 1069b63e699910262e7cbc208701c9184075244d Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 91d7d90c47da..94107bf62251 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.51.0 + From bc1aebfa14d9a8ac32d65a7df20c3bafc6337c41 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Sep 2025 14:10:06 +0200 Subject: [PATCH 122/236] Add config for v6.16 Based on the current v6.15 config --- configs/surface-6.16.config | 85 +++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 configs/surface-6.16.config diff --git a/configs/surface-6.16.config b/configs/surface-6.16.config new file mode 100644 index 0000000000..a026c661b5 --- /dev/null +++ b/configs/surface-6.16.config @@ -0,0 +1,85 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +CONFIG_RTC_DRV_SURFACE=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m +CONFIG_INTEL_THC_HID=m +CONFIG_INTEL_QUICKSPI=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m From 35f8449d5f9351db93447129fab67f22e8b73d3a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Sep 2025 14:11:07 +0200 Subject: [PATCH 123/236] Add config for v6.17 Based on the current v6.16 config --- configs/surface-6.17.config | 85 +++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 configs/surface-6.17.config diff --git a/configs/surface-6.17.config b/configs/surface-6.17.config new file mode 100644 index 0000000000..a026c661b5 --- /dev/null +++ b/configs/surface-6.17.config @@ -0,0 +1,85 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +CONFIG_RTC_DRV_SURFACE=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m +CONFIG_INTEL_THC_HID=m +CONFIG_INTEL_QUICKSPI=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m From b5d9eb7a1ec6bcdb8f87c52cfb831cfb25870f1f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Sep 2025 18:31:29 +0200 Subject: [PATCH 124/236] Update Arch Linux kernel to v6.16.9 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- pkg/arch/kernel/0007-surface-sam.patch | 2 +- .../kernel/0008-surface-sam-over-hid.patch | 2 +- pkg/arch/kernel/0009-surface-button.patch | 2 +- pkg/arch/kernel/0010-surface-typecover.patch | 2 +- pkg/arch/kernel/0011-surface-shutdown.patch | 2 +- pkg/arch/kernel/0012-surface-gpe.patch | 2 +- pkg/arch/kernel/0013-cameras.patch | 2 +- pkg/arch/kernel/0014-amd-gpio.patch | 2 +- pkg/arch/kernel/0015-rtc.patch | 2 +- pkg/arch/kernel/PKGBUILD | 38 +- pkg/arch/kernel/config | 729 ++++++++++++------ pkg/arch/kernel/surface.config | 2 +- 18 files changed, 544 insertions(+), 255 deletions(-) diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index b7e342e784..050a3810f4 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.15/0001-secureboot.patch \ No newline at end of file +../../../patches/6.16/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3.patch b/pkg/arch/kernel/0002-surface3.patch index 4c1981bd89..81bf491408 120000 --- a/pkg/arch/kernel/0002-surface3.patch +++ b/pkg/arch/kernel/0002-surface3.patch @@ -1 +1 @@ -../../../patches/6.15/0002-surface3.patch \ No newline at end of file +../../../patches/6.16/0002-surface3.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index 13d724e5ae..2365db75c3 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.15/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.16/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index 1c63455ed5..e64c2193b7 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.15/0004-ath10k.patch \ No newline at end of file +../../../patches/6.16/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index 897a46c64e..86d6a9ee26 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.15/0005-ipts.patch \ No newline at end of file +../../../patches/6.16/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index 01c5e06b81..153815084d 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.15/0006-ithc.patch \ No newline at end of file +../../../patches/6.16/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch index 516a14dcb7..53b3165a25 120000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -1 +1 @@ -../../../patches/6.15/0007-surface-sam.patch \ No newline at end of file +../../../patches/6.16/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch index c4a1aa9b50..23b25d9ed5 120000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -1 +1 @@ -../../../patches/6.15/0008-surface-sam-over-hid.patch \ No newline at end of file +../../../patches/6.16/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch index 5405d95fa7..e47f028209 120000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -1 +1 @@ -../../../patches/6.15/0009-surface-button.patch \ No newline at end of file +../../../patches/6.16/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch index f59090d526..66b94b0f30 120000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -1 +1 @@ -../../../patches/6.15/0010-surface-typecover.patch \ No newline at end of file +../../../patches/6.16/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch index e47d476e18..457d60b3e8 120000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -1 +1 @@ -../../../patches/6.15/0011-surface-shutdown.patch \ No newline at end of file +../../../patches/6.16/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch index 43a06eef61..db761cbfc8 120000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -1 +1 @@ -../../../patches/6.15/0012-surface-gpe.patch \ No newline at end of file +../../../patches/6.16/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch index 7b7d8ee7c9..90eef5fd00 120000 --- a/pkg/arch/kernel/0013-cameras.patch +++ b/pkg/arch/kernel/0013-cameras.patch @@ -1 +1 @@ -../../../patches/6.15/0013-cameras.patch \ No newline at end of file +../../../patches/6.16/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch index da4f80ad89..1d9ae12f3c 120000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -1 +1 @@ -../../../patches/6.15/0014-amd-gpio.patch \ No newline at end of file +../../../patches/6.16/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch index 57a4abf094..a81a0efb55 120000 --- a/pkg/arch/kernel/0015-rtc.patch +++ b/pkg/arch/kernel/0015-rtc.patch @@ -1 +1 @@ -../../../patches/6.15/0015-rtc.patch \ No newline at end of file +../../../patches/6.16/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 0e82bc28da..c54d0bbc98 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,8 +3,8 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.15.3.arch1 -pkgrel=2 +pkgver=6.16.9.arch1 +pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -57,25 +57,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('13443654c25cebb5b3e462a02cdb9b5cd47fe3e45331f06440a9c0d9e9236e7b' - 'a6a234cd982d21f0d7daa3ba921293e450abd87ff5d7474d4a153b3f34cfabc5' +sha256sums=('0b4d356f46d3f7ed9550bde02582d923c54fec1e9711ae8652ec2883f25c70fc' + '746810cf2462423b7f680c5eec9236f71399c02501a58bba8871fab70e693815' 'ee110be98c41a45302b2b81b037e3c4392ea7f142282e28400ac67b37455d42a' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - 'fcdde6d5b82ee4136bf848d0c15fd3ce9ad1c49b58208cd625e1d5d42b9d244f' - '631c3fd1fea46ab9b110eaea6cfa3ed5d7098152858bb082bf66853c1ef600d2' - 'aa44352a89daa2498ed441c4538e8bbcb651ff4804ad1c805830c1f61590e4d5' - 'a49120a04cb6d4276f03d0e86d755cf9ab32bb7ab916ad985a89862c0a35f05d' - '1bb9c0cf2e0dfc139705fc9fac49ff34247c3165ca3f5017dd96c22ff7c7cc60' - '51917f768432de254f1a554a33fbe988255203dc661a92fd089cda1520be4b08' - 'db9ad75ac934a40eac39721e2df8ca9e9ffb587c3aedb8e368d9f0268840a06d' - '6bdbcaa3a29c599adab4ed7d66ef65d827d137a63c813bd00c2c27592999ba5b' - '2dd8347510f0fe5cafe698d4f63eac7c017d137dd5ce2fcf47c874232485e734' - 'eaaa286bc210bfe79263a9bbf9fa16feff71c57733f9ea1571160dd276f5151e' - '24c14f2719638469feff9f31edf0f00f94ed9c0d226129a9c653927df15f2fb0' - '0188ec1dcb0b86006cde4b964d0952f8b9c77b1794cf99c614d9743869f8aefa' - 'cc1fd9ad9b15baabe33f3361adb97b7b0868a39e1146458e71ce0fa8978e1bca' - '1f30c81a4a60d803f2ff19ad72174010b3fda2edd0d9ebba803de7f8fa77647c' - '3381f58ec4cb0f5ef240e48a31a74af6205be186a1378f4ab706a376f8cc4df2') + '586a8ef0b697205949c1b34bd0682c58a8fe8aa1fd1eebfe8b3974726e2e8687' + 'df38a268cfe60e56204d0077c496eba68b5cbaaf7c61348c3e8d979438333dcd' + '5e3c0f9fe3ac37a691871ebcb28e131de92a60f85c8493472c0e3512921c94ee' + '98c97c77274d453401388092913bf94eaf4de43e352a1af3a413f05e9366bd90' + 'fbff043a27297e8ca799fd57922f517eefedf512fb9caca8cad4abe21ce06aa8' + 'c317a3bd310ed8a39d04e9531e512c986b6b53c47dcdba0ae7b9901ffa43feb4' + 'adfaba77c6e10dc5c7bf346af213cd0fd89b9e7c9411f1ded4a77c2aa9eca2f5' + 'f9044581ded23904891f19d29bafaa22f990899f57ab282edb1ea21468ba3736' + 'd694b9daeede5aa1a455018e1ec5c17ecda16b3f69ee24b269b6e13d55767e42' + 'fcdb74c0d76731c3a9e48952723696334931f11ea4f90688a826511742e72f79' + 'd98cd22320c7ef5a25c2869247f749d410dbbc699cb5eea391af395f7eae1324' + '4e3026416c2b6d090a2cb5d4ca90e48f1d12b754a89beedebab70b51ab0b8bdf' + 'e7de83a2c5c4bd812744c1e1a43e75fae5e105f5c9360c7b1bca3ce83bf8a761' + '4b649582d6dce4853bf39faac75ff103d8b8d62e9979e74a01f28f61fc043e54' + '34b70e5dad472978844a02d88bf64d49c81594e431729ec686e30c5a14eb7b8b') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index 456086c376..eb0d9e52f9 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,26 +1,32 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.12.4-arch1 Kernel Configuration +# Linux/x86 6.16.9-arch1 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="gcc (GCC) 14.2.1 20240910" +CONFIG_CC_VERSION_TEXT="gcc (GCC) 15.2.1 20250813" CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=140201 +CONFIG_GCC_VERSION=150201 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y -CONFIG_AS_VERSION=24300 +CONFIG_AS_VERSION=24500 CONFIG_LD_IS_BFD=y -CONFIG_LD_VERSION=24300 +CONFIG_LD_VERSION=24500 CONFIG_LLD_VERSION=0 -CONFIG_RUSTC_VERSION=0 -CONFIG_RUSTC_LLVM_VERSION=0 +CONFIG_RUSTC_VERSION=109000 +CONFIG_RUST_IS_AVAILABLE=y +CONFIG_RUSTC_LLVM_VERSION=200108 CONFIG_CC_CAN_LINK=y -CONFIG_CC_CAN_LINK_STATIC=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=127 +CONFIG_CC_HAS_COUNTED_BY=y +CONFIG_CC_HAS_MULTIDIMENSIONAL_NONSTRING=y +CONFIG_LD_CAN_USE_KEEP_IN_OVERLAY=y +CONFIG_RUSTC_HAS_COERCE_POINTEE=y +CONFIG_RUSTC_HAS_SPAN_FILE=y +CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES=y +CONFIG_PAHOLE_VERSION=130 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -57,7 +63,6 @@ CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE_SYSCTL=y CONFIG_WATCH_QUEUE=y CONFIG_CROSS_MEMORY_ATTACH=y -# CONFIG_USELIB is not set CONFIG_AUDIT=y CONFIG_HAVE_ARCH_AUDITSYSCALL=y CONFIG_AUDITSYSCALL=y @@ -77,7 +82,6 @@ CONFIG_IRQ_DOMAIN=y CONFIG_IRQ_SIM=y CONFIG_IRQ_DOMAIN_HIERARCHY=y CONFIG_GENERIC_MSI_IRQ=y -CONFIG_IRQ_MSI_IOMMU=y CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y CONFIG_GENERIC_IRQ_RESERVATION_MODE=y CONFIG_GENERIC_IRQ_STAT_SNAPSHOT=y @@ -88,7 +92,6 @@ CONFIG_SPARSE_IRQ=y CONFIG_CLOCKSOURCE_WATCHDOG=y CONFIG_ARCH_CLOCKSOURCE_INIT=y -CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y @@ -132,9 +135,11 @@ CONFIG_BPF_LSM=y # end of BPF subsystem CONFIG_PREEMPT_BUILD=y +CONFIG_ARCH_HAS_PREEMPT_LAZY=y # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y +# CONFIG_PREEMPT_LAZY is not set CONFIG_PREEMPT_COUNT=y CONFIG_PREEMPTION=y CONFIG_PREEMPT_DYNAMIC=y @@ -167,6 +172,7 @@ CONFIG_TREE_RCU=y CONFIG_PREEMPT_RCU=y CONFIG_RCU_EXPERT=y CONFIG_TREE_SRCU=y +# CONFIG_FORCE_NEED_SRCU_NMI_SAFE is not set CONFIG_TASKS_RCU_GENERIC=y # CONFIG_FORCE_TASKS_RCU is not set CONFIG_NEED_TASKS_RCU=y @@ -235,11 +241,11 @@ CONFIG_SCHED_MM_CID=y CONFIG_UCLAMP_TASK_GROUP=y CONFIG_CGROUP_PIDS=y CONFIG_CGROUP_RDMA=y +CONFIG_CGROUP_DMEM=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_HUGETLB=y CONFIG_CPUSETS=y # CONFIG_CPUSETS_V1 is not set -CONFIG_PROC_PID_CPUSET=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_PERF=y @@ -252,7 +258,6 @@ CONFIG_UTS_NS=y CONFIG_TIME_NS=y CONFIG_IPC_NS=y CONFIG_USER_NS=y -CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_PID_NS=y CONFIG_NET_NS=y CONFIG_CHECKPOINT_RESTORE=y @@ -278,12 +283,12 @@ CONFIG_LD_ORPHAN_WARN_LEVEL="warn" CONFIG_SYSCTL=y CONFIG_HAVE_UID16=y CONFIG_SYSCTL_EXCEPTION_TRACE=y +# CONFIG_SYSFS_SYSCALL is not set CONFIG_HAVE_PCSPKR_PLATFORM=y # CONFIG_EXPERT is not set CONFIG_UID16=y CONFIG_MULTIUSER=y CONFIG_SGETMASK_SYSCALL=y -CONFIG_SYSFS_SYSCALL=y CONFIG_FHANDLE=y CONFIG_POSIX_TIMERS=y CONFIG_PRINTK=y @@ -292,6 +297,7 @@ CONFIG_ELF_CORE=y CONFIG_PCSPKR_PLATFORM=y CONFIG_FUTEX=y CONFIG_FUTEX_PI=y +CONFIG_FUTEX_MPOL=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y CONFIG_TIMERFD=y @@ -307,8 +313,8 @@ CONFIG_CACHESTAT_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_SELFTEST is not set CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS=y CONFIG_HAVE_PERF_EVENTS=y CONFIG_GUEST_PERF_EVENTS=y @@ -321,6 +327,9 @@ CONFIG_PERF_EVENTS=y CONFIG_SYSTEM_DATA_VERIFICATION=y CONFIG_PROFILING=y +CONFIG_RUST=y +CONFIG_RUSTC_VERSION_TEXT="rustc 1.90.0 (1159e78c4 2025-09-14) (Arch Linux rust 1:1.90.0-3)" +CONFIG_BINDGEN_VERSION_TEXT="bindgen 0.72.0" CONFIG_TRACEPOINTS=y # @@ -335,7 +344,10 @@ CONFIG_KEXEC_SIG=y # CONFIG_KEXEC_SIG_FORCE is not set CONFIG_KEXEC_BZIMAGE_VERIFY_SIG=y CONFIG_KEXEC_JUMP=y +CONFIG_KEXEC_HANDOVER=y CONFIG_CRASH_DUMP=y +CONFIG_CRASH_DM_CRYPT=y +CONFIG_CRASH_DM_CRYPT_CONFIGS=y CONFIG_CRASH_HOTPLUG=y CONFIG_CRASH_MAX_MEMORY_RANGES=8192 # end of Kexec and crash features @@ -368,7 +380,6 @@ CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_FIX_EARLYCON_MEM=y CONFIG_DYNAMIC_PHYSICAL_MASK=y CONFIG_PGTABLE_LEVELS=5 -CONFIG_CC_HAS_SANE_STACKPROTECTOR=y # # Processor type and features @@ -413,21 +424,19 @@ CONFIG_PARAVIRT_CLOCK=y CONFIG_JAILHOUSE_GUEST=y CONFIG_ACRN_GUEST=y CONFIG_INTEL_TDX_GUEST=y -# CONFIG_MK8 is not set -# CONFIG_MPSC is not set -# CONFIG_MCORE2 is not set -# CONFIG_MATOM is not set -CONFIG_GENERIC_CPU=y +CONFIG_CC_HAS_MARCH_NATIVE=y +# CONFIG_X86_NATIVE_CPU is not set CONFIG_X86_INTERNODE_CACHE_SHIFT=6 CONFIG_X86_L1_CACHE_SHIFT=6 CONFIG_X86_TSC=y CONFIG_X86_HAVE_PAE=y -CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CX8=y CONFIG_X86_CMOV=y CONFIG_X86_MINIMUM_CPU_FAMILY=64 CONFIG_X86_DEBUGCTLMSR=y CONFIG_IA32_FEAT_CTL=y CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_BROADCAST_TLB_FLUSH=y CONFIG_CPU_SUP_INTEL=y CONFIG_CPU_SUP_AMD=y CONFIG_CPU_SUP_HYGON=y @@ -477,7 +486,6 @@ CONFIG_MICROCODE=y # CONFIG_MICROCODE_LATE_LOADING is not set CONFIG_X86_MSR=y CONFIG_X86_CPUID=y -CONFIG_X86_5LEVEL=y CONFIG_X86_DIRECT_GBPAGES=y CONFIG_X86_CPA_STATISTICS=y CONFIG_X86_MEM_ENCRYPT=y @@ -518,9 +526,9 @@ CONFIG_EFI_MIXED=y CONFIG_EFI_RUNTIME_MAP=y # CONFIG_HZ_100 is not set # CONFIG_HZ_250 is not set -CONFIG_HZ_300=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=300 +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_SCHED_HRTICK=y CONFIG_ARCH_SUPPORTS_KEXEC=y CONFIG_ARCH_SUPPORTS_KEXEC_FILE=y @@ -530,6 +538,7 @@ CONFIG_ARCH_SUPPORTS_KEXEC_SIG=y CONFIG_ARCH_SUPPORTS_KEXEC_SIG_FORCE=y CONFIG_ARCH_SUPPORTS_KEXEC_BZIMAGE_VERIFY_SIG=y CONFIG_ARCH_SUPPORTS_KEXEC_JUMP=y +CONFIG_ARCH_SUPPORTS_KEXEC_HANDOVER=y CONFIG_ARCH_SUPPORTS_CRASH_DUMP=y CONFIG_ARCH_DEFAULT_CRASH_DUMP=y CONFIG_ARCH_SUPPORTS_CRASH_HOTPLUG=y @@ -539,7 +548,6 @@ CONFIG_RELOCATABLE=y CONFIG_RANDOMIZE_BASE=y CONFIG_X86_NEED_RELOCS=y CONFIG_PHYSICAL_ALIGN=0x200000 -CONFIG_DYNAMIC_MEMORY_LAYOUT=y CONFIG_RANDOMIZE_MEMORY=y CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa CONFIG_HOTPLUG_CPU=y @@ -551,6 +559,7 @@ CONFIG_MODIFY_LDT_SYSCALL=y # CONFIG_STRICT_SIGALTSTACK_SIZE is not set CONFIG_HAVE_LIVEPATCH=y # CONFIG_LIVEPATCH is not set +CONFIG_X86_BUS_LOCK_DETECT=y # end of Processor type and features CONFIG_CC_HAS_NAMED_AS=y @@ -588,6 +597,9 @@ CONFIG_MITIGATION_SPECTRE_V1=y CONFIG_MITIGATION_SPECTRE_V2=y CONFIG_MITIGATION_SRBDS=y CONFIG_MITIGATION_SSB=y +CONFIG_MITIGATION_ITS=y +CONFIG_MITIGATION_TSA=y +CONFIG_MITIGATION_VMSCAPE=y CONFIG_ARCH_HAS_ADD_PAGES=y # @@ -633,6 +645,7 @@ CONFIG_ACPI_FPDT=y CONFIG_ACPI_LPIT=y CONFIG_ACPI_SLEEP=y CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y +CONFIG_ACPI_EC=y CONFIG_ACPI_EC_DEBUGFS=m CONFIG_ACPI_AC=y CONFIG_ACPI_BATTERY=y @@ -685,6 +698,7 @@ CONFIG_ACPI_CONFIGFS=m CONFIG_ACPI_PFRUT=m CONFIG_ACPI_PCC=y CONFIG_ACPI_FFH=y +CONFIG_ACPI_MRRM=y CONFIG_PMIC_OPREGION=y CONFIG_BYTCRC_PMIC_OPREGION=y CONFIG_CHTCRC_PMIC_OPREGION=y @@ -734,6 +748,7 @@ CONFIG_X86_P4_CLOCKMOD=m # shared options # CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_CPUFREQ_ARCH_CUR_FREQ=y # end of CPU Frequency scaling # @@ -759,6 +774,7 @@ CONFIG_PCI_XEN=y CONFIG_MMCONF_FAM10H=y CONFIG_ISA_DMA_API=y CONFIG_AMD_NB=y +CONFIG_AMD_NODE=y # end of Bus options (PCI etc.) # @@ -788,12 +804,14 @@ CONFIG_KVM_VFIO=y CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY=y CONFIG_KVM_COMPAT=y -CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_IRQ_BYPASS=m CONFIG_HAVE_KVM_NO_POLL=y CONFIG_KVM_XFER_TO_GUEST_WORK=y CONFIG_HAVE_KVM_PM_NOTIFIER=y CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y CONFIG_KVM_GENERIC_MMU_NOTIFIER=y +CONFIG_KVM_ELIDE_TLB_FLUSH_IF_YOUNG=y +CONFIG_KVM_MMU_LOCKLESS_AGING=y CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES=y CONFIG_KVM_PRIVATE_MEM=y CONFIG_KVM_GENERIC_PRIVATE_MEM=y @@ -811,10 +829,24 @@ CONFIG_KVM_HYPERV=y CONFIG_KVM_XEN=y CONFIG_KVM_EXTERNAL_WRITE_TRACKING=y CONFIG_KVM_MAX_NR_VCPUS=1024 +CONFIG_X86_REQUIRED_FEATURE_ALWAYS=y +CONFIG_X86_REQUIRED_FEATURE_NOPL=y +CONFIG_X86_REQUIRED_FEATURE_CX8=y +CONFIG_X86_REQUIRED_FEATURE_CMOV=y +CONFIG_X86_REQUIRED_FEATURE_CPUID=y +CONFIG_X86_REQUIRED_FEATURE_FPU=y +CONFIG_X86_REQUIRED_FEATURE_PAE=y +CONFIG_X86_REQUIRED_FEATURE_MSR=y +CONFIG_X86_REQUIRED_FEATURE_FXSR=y +CONFIG_X86_REQUIRED_FEATURE_XMM=y +CONFIG_X86_REQUIRED_FEATURE_XMM2=y +CONFIG_X86_REQUIRED_FEATURE_LM=y +CONFIG_X86_DISABLED_FEATURE_VME=y +CONFIG_X86_DISABLED_FEATURE_K6_MTRR=y +CONFIG_X86_DISABLED_FEATURE_CYRIX_ARR=y +CONFIG_X86_DISABLED_FEATURE_CENTAUR_MCR=y +CONFIG_X86_DISABLED_FEATURE_LAM=y CONFIG_AS_AVX512=y -CONFIG_AS_SHA1_NI=y -CONFIG_AS_SHA256_NI=y -CONFIG_AS_TPAUSE=y CONFIG_AS_GFNI=y CONFIG_AS_VAES=y CONFIG_AS_VPCLMULQDQ=y @@ -882,6 +914,7 @@ CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y CONFIG_MMU_GATHER_TABLE_FREE=y CONFIG_MMU_GATHER_RCU_TABLE_FREE=y CONFIG_MMU_GATHER_MERGE_VMAS=y +CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM=y CONFIG_MMU_LAZY_TLB_REFCOUNT=y CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y CONFIG_ARCH_HAVE_EXTRA_ELF_NOTES=y @@ -903,6 +936,8 @@ CONFIG_STACKPROTECTOR_STRONG=y CONFIG_ARCH_SUPPORTS_LTO_CLANG=y CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y CONFIG_LTO_NONE=y +CONFIG_ARCH_SUPPORTS_AUTOFDO_CLANG=y +CONFIG_ARCH_SUPPORTS_PROPELLER_CLANG=y CONFIG_ARCH_SUPPORTS_CFI_CLANG=y CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y CONFIG_HAVE_CONTEXT_TRACKING_USER=y @@ -920,15 +955,16 @@ CONFIG_ARCH_WANT_PMD_MKWRITE=y CONFIG_HAVE_ARCH_SOFT_DIRTY=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_EXECMEM_ROX=y CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y CONFIG_SOFTIRQ_ON_OWN_STACK=y CONFIG_ARCH_HAS_ELF_RANDOMIZE=y CONFIG_HAVE_ARCH_MMAP_RND_BITS=y CONFIG_HAVE_EXIT_THREAD=y -CONFIG_ARCH_MMAP_RND_BITS=32 +CONFIG_ARCH_MMAP_RND_BITS=28 CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y -CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y CONFIG_HAVE_PAGE_SIZE_4KB=y CONFIG_PAGE_SIZE_4KB=y @@ -956,6 +992,7 @@ CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y CONFIG_STRICT_KERNEL_RWX=y CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y CONFIG_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_CPU_RESCTRL=y CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y CONFIG_ARCH_USE_MEMREMAP_PROT=y CONFIG_LOCK_EVENT_COUNTS=y @@ -975,6 +1012,7 @@ CONFIG_HAVE_ARCH_NODE_DEV_GROUP=y CONFIG_ARCH_HAS_HW_PTE_YOUNG=y CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y CONFIG_ARCH_HAS_KERNEL_FPU_SUPPORT=y +CONFIG_ARCH_VMLINUX_NEEDS_RELOCS=y # # GCOV-based kernel profiling @@ -1073,8 +1111,6 @@ CONFIG_EFI_PARTITION=y # CONFIG_CMDLINE_PARTITION is not set # end of Partition Types -CONFIG_BLK_MQ_PCI=y -CONFIG_BLK_MQ_VIRTIO=y CONFIG_BLK_PM=y CONFIG_BLOCK_HOLDER_DEPRECATED=y CONFIG_BLK_MQ_STACKING=y @@ -1124,7 +1160,7 @@ CONFIG_COREDUMP=y CONFIG_ZPOOL=y CONFIG_SWAP=y CONFIG_ZSWAP=y -# CONFIG_ZSWAP_DEFAULT_ON is not set +CONFIG_ZSWAP_DEFAULT_ON=y CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y # CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set # CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO is not set @@ -1133,12 +1169,8 @@ CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y # CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4HC is not set CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y CONFIG_ZSWAP_COMPRESSOR_DEFAULT="zstd" -# CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD is not set -# CONFIG_ZSWAP_ZPOOL_DEFAULT_Z3FOLD_DEPRECATED is not set CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC=y CONFIG_ZSWAP_ZPOOL_DEFAULT="zsmalloc" -CONFIG_ZBUD=m -# CONFIG_Z3FOLD_DEPRECATED is not set CONFIG_ZSMALLOC=y CONFIG_ZSMALLOC_STAT=y CONFIG_ZSMALLOC_CHAIN_SIZE=8 @@ -1147,6 +1179,7 @@ CONFIG_ZSMALLOC_CHAIN_SIZE=8 # Slab allocator options # CONFIG_SLUB=y +CONFIG_KVFREE_RCU_BATCHED=y CONFIG_SLAB_MERGE_DEFAULT=y CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y @@ -1162,9 +1195,12 @@ CONFIG_SPARSEMEM=y CONFIG_SPARSEMEM_EXTREME=y CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_PREINIT=y CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP=y CONFIG_ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP=y +CONFIG_ARCH_WANT_HUGETLB_VMEMMAP_PREINIT=y CONFIG_HAVE_GUP_FAST=y +CONFIG_MEMBLOCK_KHO_SCRATCH=y CONFIG_NUMA_KEEP_MEMINFO=y CONFIG_MEMORY_ISOLATION=y CONFIG_EXCLUSIVE_SYSTEM_RAM=y @@ -1172,7 +1208,10 @@ CONFIG_HAVE_BOOTMEM_INFO_NODE=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y +# CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE is not set +CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO=y +# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_KERNEL is not set +# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE is not set CONFIG_MEMORY_HOTREMOVE=y CONFIG_MHP_MEMMAP_ON_MEMORY=y CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y @@ -1199,12 +1238,15 @@ CONFIG_MEMORY_FAILURE=y CONFIG_HWPOISON_INJECT=m CONFIG_ARCH_WANT_GENERAL_HUGETLB=y CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_MM_ID=y CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y # CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set # CONFIG_TRANSPARENT_HUGEPAGE_NEVER is not set CONFIG_THP_SWAP=y CONFIG_READ_ONLY_THP_FOR_FS=y +# CONFIG_NO_PAGE_MAPCOUNT is not set +CONFIG_PAGE_MAPCOUNT=y CONFIG_PGTABLE_HAS_HUGE_LEAVES=y CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP=y CONFIG_ARCH_SUPPORTS_PMD_PFNMAP=y @@ -1217,6 +1259,7 @@ CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_CMA_SYSFS=y CONFIG_CMA_AREAS=7 +CONFIG_PAGE_BLOCK_ORDER=10 CONFIG_MEM_SOFT_DIRTY=y CONFIG_GENERIC_EARLY_IOREMAP=y # CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set @@ -1259,6 +1302,9 @@ CONFIG_IOMMU_MM_DATA=y CONFIG_EXECMEM=y CONFIG_NUMA_MEMBLKS=y # CONFIG_NUMA_EMU is not set +CONFIG_ARCH_HAS_USER_SHADOW_STACK=y +CONFIG_ARCH_SUPPORTS_PT_RECLAIM=y +CONFIG_PT_RECLAIM=y # # Data Access Monitoring @@ -1267,7 +1313,6 @@ CONFIG_DAMON=y CONFIG_DAMON_VADDR=y CONFIG_DAMON_PADDR=y CONFIG_DAMON_SYSFS=y -# CONFIG_DAMON_DBGFS_DEPRECATED is not set CONFIG_DAMON_RECLAIM=y CONFIG_DAMON_LRU_SORT=y # end of Data Access Monitoring @@ -1282,6 +1327,8 @@ CONFIG_NET_REDIRECT=y CONFIG_SKB_DECRYPTED=y CONFIG_SKB_EXTENSIONS=y CONFIG_NET_DEVMEM=y +CONFIG_NET_SHAPER=y +CONFIG_NET_CRC32C=y # # Networking options @@ -1308,6 +1355,7 @@ CONFIG_XFRM_ESP=m CONFIG_XFRM_IPCOMP=m CONFIG_NET_KEY=m CONFIG_NET_KEY_MIGRATE=y +CONFIG_XFRM_IPTFS=m CONFIG_XFRM_ESPINTCP=y CONFIG_SMC=m CONFIG_SMC_DIAG=m @@ -1772,7 +1820,6 @@ CONFIG_BRIDGE_EBT_REDIRECT=m CONFIG_BRIDGE_EBT_SNAT=m CONFIG_BRIDGE_EBT_LOG=m CONFIG_BRIDGE_EBT_NFLOG=m -# CONFIG_IP_DCCP is not set CONFIG_IP_SCTP=m # CONFIG_SCTP_DBG_OBJCNT is not set # CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set @@ -1900,6 +1947,7 @@ CONFIG_NET_SCH_FQ_PIE=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_SCH_PLUG=m CONFIG_NET_SCH_ETS=m +CONFIG_NET_SCH_BPF=y CONFIG_NET_SCH_DEFAULT=y # CONFIG_DEFAULT_FQ is not set # CONFIG_DEFAULT_CODEL is not set @@ -2118,6 +2166,7 @@ CONFIG_AF_RXRPC_IPV6=y # CONFIG_AF_RXRPC_INJECT_RX_DELAY is not set CONFIG_AF_RXRPC_DEBUG=y CONFIG_RXKAD=y +CONFIG_RXGK=y # CONFIG_RXPERF is not set CONFIG_AF_KCM=m CONFIG_STREAM_PARSER=y @@ -2128,7 +2177,6 @@ CONFIG_WIRELESS=y CONFIG_WIRELESS_EXT=y CONFIG_WEXT_CORE=y CONFIG_WEXT_PROC=y -CONFIG_WEXT_SPY=y CONFIG_WEXT_PRIV=y CONFIG_CFG80211=m # CONFIG_NL80211_TESTMODE is not set @@ -2139,12 +2187,6 @@ CONFIG_CFG80211_DEFAULT_PS=y CONFIG_CFG80211_DEBUGFS=y CONFIG_CFG80211_CRDA_SUPPORT=y CONFIG_CFG80211_WEXT=y -CONFIG_CFG80211_WEXT_EXPORT=y -CONFIG_LIB80211=m -CONFIG_LIB80211_CRYPT_WEP=m -CONFIG_LIB80211_CRYPT_CCMP=m -CONFIG_LIB80211_CRYPT_TKIP=m -# CONFIG_LIB80211_DEBUG is not set CONFIG_MAC80211=m CONFIG_MAC80211_HAS_RC=y CONFIG_MAC80211_RC_MINSTREL=y @@ -2164,7 +2206,7 @@ CONFIG_NET_9P=m CONFIG_NET_9P_FD=m CONFIG_NET_9P_VIRTIO=m CONFIG_NET_9P_XEN=m -CONFIG_NET_9P_USBG=y +CONFIG_NET_9P_USBG=m CONFIG_NET_9P_RDMA=m # CONFIG_NET_9P_DEBUG is not set # CONFIG_CAIF is not set @@ -2236,8 +2278,6 @@ CONFIG_ETHTOOL_NETLINK=y # # Device Drivers # -CONFIG_HAVE_EISA=y -# CONFIG_EISA is not set CONFIG_HAVE_PCI=y CONFIG_GENERIC_PCI_IOMAP=y CONFIG_PCI=y @@ -2271,6 +2311,7 @@ CONFIG_PCI_IOV=y CONFIG_PCI_NPEM=y CONFIG_PCI_PRI=y CONFIG_PCI_PASID=y +CONFIG_PCIE_TPH=y CONFIG_PCI_P2PDMA=y CONFIG_PCI_LABEL=y CONFIG_PCI_HYPERV=m @@ -2282,6 +2323,7 @@ CONFIG_HOTPLUG_PCI_ACPI_IBM=m CONFIG_HOTPLUG_PCI_CPCI=y CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +# CONFIG_HOTPLUG_PCI_OCTEONEP is not set CONFIG_HOTPLUG_PCI_SHPC=y # @@ -2299,6 +2341,7 @@ CONFIG_PCI_HYPERV_INTERFACE=m # DesignWare-based PCIe controllers # CONFIG_PCIE_DW=y +CONFIG_PCIE_DW_DEBUGFS=y CONFIG_PCIE_DW_HOST=y CONFIG_PCI_MESON=m CONFIG_PCIE_DW_PLAT=y @@ -2328,16 +2371,20 @@ CONFIG_PCIE_DW_PLAT_HOST=y CONFIG_PCI_SW_SWITCHTEC=m # end of PCI switch controller drivers +CONFIG_PCI_PWRCTRL=m +CONFIG_PCI_PWRCTRL_SLOT=m CONFIG_CXL_BUS=m CONFIG_CXL_PCI=m # CONFIG_CXL_MEM_RAW_COMMANDS is not set CONFIG_CXL_ACPI=m CONFIG_CXL_PMEM=m CONFIG_CXL_MEM=m +CONFIG_CXL_FEATURES=y CONFIG_CXL_PORT=m CONFIG_CXL_SUSPEND=y CONFIG_CXL_REGION=y # CONFIG_CXL_REGION_INVALIDATION_TEST is not set +CONFIG_CXL_MCE=y CONFIG_PCCARD=m CONFIG_PCMCIA=m CONFIG_PCMCIA_LOAD_CIS=y @@ -2373,6 +2420,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER=y CONFIG_FW_LOADER_DEBUG=y +CONFIG_RUST_FW_LOADER_ABSTRACTIONS=y CONFIG_FW_LOADER_PAGED_BUF=y CONFIG_FW_LOADER_SYSFS=y CONFIG_EXTRA_FIRMWARE="" @@ -2493,6 +2541,10 @@ CONFIG_UEFI_CPER_X86=y # # Qualcomm firmware drivers # +CONFIG_QCOM_SCM=m +CONFIG_QCOM_TZMEM=m +CONFIG_QCOM_TZMEM_MODE_GENERIC=y +# CONFIG_QCOM_TZMEM_MODE_SHMBRIDGE is not set # end of Qualcomm firmware drivers # @@ -2501,6 +2553,9 @@ CONFIG_UEFI_CPER_X86=y # end of Tegra firmware driver # end of Firmware Drivers +CONFIG_FWCTL=m +CONFIG_FWCTL_MLX5=m +CONFIG_FWCTL_PDS=m CONFIG_GNSS=m CONFIG_GNSS_SERIAL=m CONFIG_GNSS_MTK_SERIAL=m @@ -2693,13 +2748,15 @@ CONFIG_CDROM_PKTCDVD_BUFFERS=8 CONFIG_ATA_OVER_ETH=m CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_BLKDEV_BACKEND=m -CONFIG_VIRTIO_BLK=m +CONFIG_VIRTIO_BLK=y +# CONFIG_BLK_DEV_RUST_NULL is not set CONFIG_BLK_DEV_RBD=m CONFIG_BLK_DEV_UBLK=m CONFIG_BLKDEV_UBLK_LEGACY_OPCODES=y CONFIG_BLK_DEV_RNBD=y CONFIG_BLK_DEV_RNBD_CLIENT=m CONFIG_BLK_DEV_RNBD_SERVER=m +CONFIG_BLK_DEV_ZONED_LOOP=m # # NVME Support @@ -2740,6 +2797,7 @@ CONFIG_AD525X_DPOT_SPI=m CONFIG_IBM_ASM=m CONFIG_PHANTOM=m CONFIG_RPMB=m +CONFIG_TI_FPC202=m CONFIG_TIFM_CORE=m CONFIG_TIFM_7XX1=m CONFIG_ICS932S401=m @@ -2762,6 +2820,7 @@ CONFIG_DW_XDATA_PCIE=m CONFIG_PCI_ENDPOINT_TEST=m CONFIG_XILINX_SDFEC=m CONFIG_MISC_RTSX=m +CONFIG_NTSYNC=m CONFIG_TPS6594_ESM=m CONFIG_TPS6594_PFSM=m CONFIG_NSM=m @@ -2783,13 +2842,6 @@ CONFIG_EEPROM_EE1004=m CONFIG_CB710_CORE=m # CONFIG_CB710_DEBUG is not set CONFIG_CB710_DEBUG_ASSUMPTIONS=y - -# -# Texas Instruments shared transport line discipline -# -CONFIG_TI_ST=m -# end of Texas Instruments shared transport line discipline - CONFIG_SENSORS_LIS3_I2C=m CONFIG_ALTERA_STAPL=m CONFIG_INTEL_MEI=m @@ -2804,7 +2856,6 @@ CONFIG_INTEL_MEI_GSC_PROXY=m CONFIG_VMWARE_VMCI=m CONFIG_GENWQE=m CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY=0 -CONFIG_ECHO=m CONFIG_BCM_VK=m CONFIG_BCM_VK_TTY=y CONFIG_MISC_ALCOR_PCI=m @@ -2816,6 +2867,9 @@ CONFIG_PVPANIC_MMIO=m CONFIG_PVPANIC_PCI=m CONFIG_GP_PCI1XXXX=m CONFIG_KEBA_CP500=m +CONFIG_KEBA_LAN9252=m +CONFIG_AMD_SBRMI_I2C=m +CONFIG_AMD_SBRMI_HWMON=y # end of Misc devices # @@ -3089,6 +3143,7 @@ CONFIG_PATA_LEGACY=m CONFIG_MD=y CONFIG_BLK_DEV_MD=m CONFIG_MD_BITMAP_FILE=y +CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID10=m @@ -3178,6 +3233,7 @@ CONFIG_BONDING=m CONFIG_DUMMY=m CONFIG_WIREGUARD=m # CONFIG_WIREGUARD_DEBUG is not set +CONFIG_OVPN=m CONFIG_EQUALIZER=m CONFIG_NET_FC=y CONFIG_IFB=m @@ -3265,6 +3321,7 @@ CONFIG_NET_DSA_MICROCHIP_KSZ_PTP=y CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI=m CONFIG_NET_DSA_MV88E6XXX=m CONFIG_NET_DSA_MV88E6XXX_PTP=y +CONFIG_NET_DSA_MV88E6XXX_LEDS=y CONFIG_NET_DSA_MSCC_FELIX_DSA_LIB=m CONFIG_NET_DSA_MSCC_OCELOT_EXT=m CONFIG_NET_DSA_MSCC_SEVILLE=m @@ -3391,8 +3448,6 @@ CONFIG_ULI526X=m CONFIG_PCMCIA_XIRCOM=m CONFIG_NET_VENDOR_DLINK=y CONFIG_DL2K=m -CONFIG_SUNDANCE=m -# CONFIG_SUNDANCE_MMIO is not set CONFIG_NET_VENDOR_EMULEX=y CONFIG_BE2NET=m CONFIG_BE2NET_HWMON=y @@ -3411,8 +3466,11 @@ CONFIG_FUN_CORE=m CONFIG_FUN_ETH=m CONFIG_NET_VENDOR_GOOGLE=y CONFIG_GVE=m +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_HIBMCGE=m CONFIG_NET_VENDOR_HUAWEI=y CONFIG_HINIC=m +CONFIG_HINIC3=m CONFIG_NET_VENDOR_I825XX=y CONFIG_NET_VENDOR_INTEL=y CONFIG_LIBETH=m @@ -3667,6 +3725,7 @@ CONFIG_SFP=m # # MII PHY device drivers # +CONFIG_AS21XXX_PHY=m CONFIG_AIR_EN8811H_PHY=m CONFIG_AMD_PHY=m CONFIG_ADIN_PHY=m @@ -3692,12 +3751,15 @@ CONFIG_MARVELL_10G_PHY=m CONFIG_MARVELL_88Q2XXX_PHY=m CONFIG_MARVELL_88X2222_PHY=m CONFIG_MAXLINEAR_GPHY=m +CONFIG_MAXLINEAR_86110_PHY=m CONFIG_MEDIATEK_GE_PHY=m # CONFIG_MEDIATEK_GE_SOC_PHY is not set +CONFIG_MTK_NET_PHYLIB=m CONFIG_MICREL_PHY=m CONFIG_MICROCHIP_T1S_PHY=m CONFIG_MICROCHIP_PHY=m CONFIG_MICROCHIP_T1_PHY=m +CONFIG_MICROCHIP_PHY_RDS_PTP=m CONFIG_MICROSEMI_PHY=m CONFIG_MOTORCOMM_PHY=m CONFIG_NATIONAL_PHY=m @@ -3711,6 +3773,7 @@ CONFIG_QCA83XX_PHY=m CONFIG_QCA808X_PHY=m CONFIG_QSEMI_PHY=m CONFIG_REALTEK_PHY=m +CONFIG_REALTEK_PHY_HWMON=y CONFIG_RENESAS_PHY=m # CONFIG_ROCKCHIP_PHY is not set CONFIG_SMSC_PHY=m @@ -3800,13 +3863,12 @@ CONFIG_CAN_UCAN=m # CONFIG_MCTP_SERIAL=m CONFIG_MCTP_TRANSPORT_I2C=m +CONFIG_MCTP_TRANSPORT_USB=m # end of MCTP Device Drivers -CONFIG_MDIO_DEVICE=m CONFIG_MDIO_BUS=m CONFIG_FWNODE_MDIO=m CONFIG_ACPI_MDIO=m -CONFIG_MDIO_DEVRES=m CONFIG_MDIO_BITBANG=m CONFIG_MDIO_BCM_UNIMAC=m CONFIG_MDIO_CAVIUM=m @@ -3962,9 +4024,11 @@ CONFIG_ATH11K_DEBUGFS=y # CONFIG_ATH11K_TRACING is not set CONFIG_ATH11K_SPECTRAL=y CONFIG_ATH12K=m +CONFIG_ATH12K_AHB=y CONFIG_ATH12K_DEBUG=y CONFIG_ATH12K_DEBUGFS=y CONFIG_ATH12K_TRACING=y +CONFIG_ATH12K_COREDUMP=y CONFIG_WLAN_VENDOR_ATMEL=y CONFIG_AT76C50X_USB=m CONFIG_WLAN_VENDOR_BROADCOM=y @@ -4035,6 +4099,7 @@ CONFIG_IWLWIFI=m CONFIG_IWLWIFI_LEDS=y CONFIG_IWLDVM=m CONFIG_IWLMVM=m +CONFIG_IWLMLD=m CONFIG_IWLWIFI_OPMODE_MODULAR=y # @@ -4172,6 +4237,10 @@ CONFIG_RTW88_8723X=m CONFIG_RTW88_8703B=m CONFIG_RTW88_8723D=m CONFIG_RTW88_8821C=m +CONFIG_RTW88_88XXA=m +CONFIG_RTW88_8821A=m +CONFIG_RTW88_8812A=m +CONFIG_RTW88_8814A=m CONFIG_RTW88_8822BE=m CONFIG_RTW88_8822BS=m CONFIG_RTW88_8822BU=m @@ -4185,8 +4254,13 @@ CONFIG_RTW88_8723DU=m CONFIG_RTW88_8821CE=m CONFIG_RTW88_8821CS=m CONFIG_RTW88_8821CU=m +CONFIG_RTW88_8821AU=m +CONFIG_RTW88_8812AU=m +CONFIG_RTW88_8814AE=m +CONFIG_RTW88_8814AU=m CONFIG_RTW88_DEBUG=y CONFIG_RTW88_DEBUGFS=y +CONFIG_RTW88_LEDS=y CONFIG_RTW89=m CONFIG_RTW89_CORE=m CONFIG_RTW89_PCI=m @@ -4297,7 +4371,7 @@ CONFIG_INPUT_LEDS=y CONFIG_INPUT_FF_MEMLESS=m CONFIG_INPUT_SPARSEKMAP=m CONFIG_INPUT_MATRIXKMAP=m -CONFIG_INPUT_VIVALDIFMAP=m +CONFIG_INPUT_VIVALDIFMAP=y # # Userland interfaces @@ -4308,7 +4382,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_EVBUG is not set # # Input Device Drivers @@ -4319,7 +4392,7 @@ CONFIG_KEYBOARD_ADP5520=m CONFIG_KEYBOARD_ADP5588=m CONFIG_KEYBOARD_ADP5589=m CONFIG_KEYBOARD_APPLESPI=m -CONFIG_KEYBOARD_ATKBD=m +CONFIG_KEYBOARD_ATKBD=y CONFIG_KEYBOARD_QT1050=m CONFIG_KEYBOARD_QT1070=m CONFIG_KEYBOARD_QT2160=m @@ -4565,7 +4638,6 @@ CONFIG_INPUT_TWL4030_VIBRA=m CONFIG_INPUT_TWL6040_VIBRA=m CONFIG_INPUT_UINPUT=m CONFIG_INPUT_PALMAS_PWRBUTTON=m -CONFIG_INPUT_PCF50633_PMU=m CONFIG_INPUT_PCF8574=m CONFIG_INPUT_PWM_BEEPER=m CONFIG_INPUT_PWM_VIBRA=m @@ -4592,6 +4664,7 @@ CONFIG_INPUT_SOC_BUTTON_ARRAY=m CONFIG_INPUT_DRV260X_HAPTICS=m CONFIG_INPUT_DRV2665_HAPTICS=m CONFIG_INPUT_DRV2667_HAPTICS=m +CONFIG_INPUT_QNAP_MCU=m CONFIG_INPUT_RAVE_SP_PWRBUTTON=m CONFIG_INPUT_RT5120_PWRKEY=m CONFIG_RMI4_CORE=m @@ -4612,14 +4685,14 @@ CONFIG_RMI4_F55=y # # Hardware I/O ports # -CONFIG_SERIO=m +CONFIG_SERIO=y CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y -CONFIG_SERIO_I8042=m +CONFIG_SERIO_I8042=y CONFIG_SERIO_SERPORT=m CONFIG_SERIO_CT82C710=m CONFIG_SERIO_PARKBD=m CONFIG_SERIO_PCIPS2=m -CONFIG_SERIO_LIBPS2=m +CONFIG_SERIO_LIBPS2=y CONFIG_SERIO_RAW=m CONFIG_SERIO_ALTERA_PS2=m CONFIG_SERIO_PS2MULT=m @@ -4678,6 +4751,7 @@ CONFIG_SERIAL_8250_RT288X=y CONFIG_SERIAL_8250_LPSS=m CONFIG_SERIAL_8250_MID=m CONFIG_SERIAL_8250_PERICOM=m +CONFIG_SERIAL_8250_NI=m # # Non-8250 serial port support @@ -4727,7 +4801,7 @@ CONFIG_SERIAL_DEV_CTRL_TTYPORT=y CONFIG_PRINTER=m CONFIG_LP_CONSOLE=y CONFIG_PPDEV=m -CONFIG_VIRTIO_CONSOLE=m +CONFIG_VIRTIO_CONSOLE=y CONFIG_IPMI_HANDLER=m CONFIG_IPMI_DMI_DECODE=y CONFIG_IPMI_PLAT_DATA=y @@ -4774,6 +4848,7 @@ CONFIG_TCG_INFINEON=m CONFIG_TCG_XEN=m CONFIG_TCG_CRB=y CONFIG_TCG_VTPM_PROXY=m +CONFIG_TCG_SVSM=m CONFIG_TCG_TIS_ST33ZP24=m CONFIG_TCG_TIS_ST33ZP24_I2C=m CONFIG_TCG_TIS_ST33ZP24_SPI=m @@ -4804,6 +4879,7 @@ CONFIG_I2C_MUX_REG=m CONFIG_I2C_MUX_MLXCPLD=m # end of Multiplexer I2C Chip support +CONFIG_I2C_ATR=m CONFIG_I2C_HELPER_AUTO=y CONFIG_I2C_SMBUS=m CONFIG_I2C_ALGOBIT=m @@ -4821,9 +4897,9 @@ CONFIG_I2C_ALI1535=m CONFIG_I2C_ALI1563=m CONFIG_I2C_ALI15X3=m CONFIG_I2C_AMD756=m -CONFIG_I2C_AMD756_S4882=m CONFIG_I2C_AMD8111=m CONFIG_I2C_AMD_MP2=m +CONFIG_I2C_AMD_ASF=m CONFIG_I2C_I801=m CONFIG_I2C_I801_MUX=y CONFIG_I2C_ISCH=m @@ -4831,7 +4907,6 @@ CONFIG_I2C_ISMT=m CONFIG_I2C_PIIX4=m CONFIG_I2C_CHT_WC=m CONFIG_I2C_NFORCE2=m -CONFIG_I2C_NFORCE2_S4985=m CONFIG_I2C_NVIDIA_GPU=m CONFIG_I2C_SIS5595=m CONFIG_I2C_SIS630=m @@ -4849,9 +4924,11 @@ CONFIG_I2C_SCMI=m # I2C system bus drivers (mostly embedded / system-on-chip) # CONFIG_I2C_CBUS_GPIO=m +CONFIG_I2C_CGBC=m CONFIG_I2C_DESIGNWARE_CORE=y CONFIG_I2C_DESIGNWARE_SLAVE=y CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_DESIGNWARE_AMDISP=m CONFIG_I2C_DESIGNWARE_BAYTRAIL=y CONFIG_I2C_DESIGNWARE_PCI=y CONFIG_I2C_EMEV2=m @@ -4900,6 +4977,7 @@ CONFIG_SPI=y # CONFIG_SPI_DEBUG is not set CONFIG_SPI_MASTER=y CONFIG_SPI_MEM=y +CONFIG_SPI_OFFLOAD=y # # SPI Master Controller Drivers @@ -4922,6 +5000,7 @@ CONFIG_SPI_GPIO=m CONFIG_SPI_INTEL=m CONFIG_SPI_INTEL_PCI=m CONFIG_SPI_INTEL_PLATFORM=m +CONFIG_SPI_KSPI2=m CONFIG_SPI_LM70_LLP=m CONFIG_SPI_LJCA=m CONFIG_SPI_MICROCHIP_CORE=m @@ -4954,6 +5033,11 @@ CONFIG_SPI_SLAVE=y CONFIG_SPI_SLAVE_TIME=m CONFIG_SPI_SLAVE_SYSTEM_CONTROL=m CONFIG_SPI_DYNAMIC=y + +# +# SPI Offload triggers +# +CONFIG_SPI_OFFLOAD_TRIGGER_PWM=m # CONFIG_SPMI is not set # CONFIG_HSI is not set CONFIG_PPS=m @@ -4966,10 +5050,9 @@ CONFIG_PPS_CLIENT_KTIMER=m CONFIG_PPS_CLIENT_LDISC=m CONFIG_PPS_CLIENT_PARPORT=m CONFIG_PPS_CLIENT_GPIO=m - -# -# PPS generators support -# +CONFIG_PPS_GENERATOR=m +# CONFIG_PPS_GENERATOR_DUMMY is not set +CONFIG_PPS_GENERATOR_TIO=m # # PTP clock support @@ -4979,6 +5062,7 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=m CONFIG_DP83640_PHY=m CONFIG_PTP_1588_CLOCK_INES=m CONFIG_PTP_1588_CLOCK_KVM=m +CONFIG_PTP_1588_CLOCK_VMCLOCK=m CONFIG_PTP_1588_CLOCK_IDT82P33=m CONFIG_PTP_1588_CLOCK_IDTCM=m CONFIG_PTP_1588_CLOCK_FC3W=m @@ -4994,6 +5078,7 @@ CONFIG_PINCONF=y CONFIG_GENERIC_PINCONF=y # CONFIG_DEBUG_PINCTRL is not set CONFIG_PINCTRL_AMD=y +CONFIG_PINCTRL_AMDISP=m CONFIG_PINCTRL_CY8C95X0=m CONFIG_PINCTRL_DA9062=m CONFIG_PINCTRL_MCP23S08_I2C=m @@ -5055,6 +5140,7 @@ CONFIG_GPIO_IDIO_16=m # # Memory mapped GPIO drivers # +CONFIG_GPIO_ALTERA=m CONFIG_GPIO_AMDPT=m CONFIG_GPIO_DWAPB=m CONFIG_GPIO_EXAR=m @@ -5063,8 +5149,10 @@ CONFIG_GPIO_GRANITERAPIDS=m CONFIG_GPIO_ICH=m CONFIG_GPIO_MB86S7X=m CONFIG_GPIO_MENZ127=m +# CONFIG_GPIO_POLARFIRE_SOC is not set CONFIG_GPIO_SIOX=m CONFIG_GPIO_TANGIER=m +CONFIG_GPIO_XILINX=m CONFIG_GPIO_AMD_FCH=m # end of Memory mapped GPIO drivers @@ -5100,8 +5188,9 @@ CONFIG_GPIO_TPIC2810=m CONFIG_GPIO_ADP5520=m CONFIG_GPIO_ARIZONA=m CONFIG_GPIO_BD9571MWV=m +CONFIG_GPIO_CGBC=m CONFIG_GPIO_CROS_EC=m -CONFIG_GPIO_CRYSTAL_COVE=m +CONFIG_GPIO_CRYSTAL_COVE=y CONFIG_GPIO_DA9052=m CONFIG_GPIO_DA9055=m CONFIG_GPIO_DLN2=m @@ -5141,6 +5230,7 @@ CONFIG_GPIO_RDC321X=m # # SPI GPIO expanders # +CONFIG_GPIO_74X164=m CONFIG_GPIO_MAX3191X=m CONFIG_GPIO_MAX7301=m CONFIG_GPIO_MC33880=m @@ -5152,6 +5242,7 @@ CONFIG_GPIO_XRA1403=m # USB GPIO expanders # CONFIG_GPIO_VIPERBOARD=m +CONFIG_GPIO_MPSSE=m # end of USB GPIO expanders # @@ -5170,6 +5261,7 @@ CONFIG_GPIO_SIM=m # CONFIG_GPIO_VIRTUSER is not set # end of GPIO Debugging utilities +CONFIG_DEV_SYNC_PROBE=m CONFIG_W1=m CONFIG_W1_CON=y @@ -5227,6 +5319,7 @@ CONFIG_WM8350_POWER=m CONFIG_TEST_POWER=m CONFIG_BATTERY_88PM860X=m CONFIG_CHARGER_ADP5061=m +CONFIG_BATTERY_CHAGALL=m CONFIG_BATTERY_CW2015=m CONFIG_BATTERY_DS2760=m CONFIG_BATTERY_DS2780=m @@ -5255,11 +5348,11 @@ CONFIG_BATTERY_MAX1720X=m CONFIG_BATTERY_MAX1721X=m CONFIG_BATTERY_TWL4030_MADC=m CONFIG_CHARGER_88PM860X=m -CONFIG_CHARGER_PCF50633=m CONFIG_BATTERY_RX51=m CONFIG_CHARGER_ISP1704=m CONFIG_CHARGER_MAX8903=m CONFIG_CHARGER_TWL4030=m +CONFIG_CHARGER_TWL6030=m CONFIG_CHARGER_LP8727=m CONFIG_CHARGER_LP8788=m CONFIG_CHARGER_GPIO=m @@ -5268,7 +5361,9 @@ CONFIG_CHARGER_LT3651=m CONFIG_CHARGER_LTC4162L=m CONFIG_CHARGER_MAX14577=m CONFIG_CHARGER_MAX77693=m +CONFIG_CHARGER_MAX77705=m CONFIG_CHARGER_MAX77976=m +CONFIG_CHARGER_MAX8971=m CONFIG_CHARGER_MAX8997=m CONFIG_CHARGER_MAX8998=m CONFIG_CHARGER_MP2629=m @@ -5294,6 +5389,7 @@ CONFIG_CHARGER_RT9471=m CONFIG_CHARGER_CROS_USBPD=m CONFIG_CHARGER_CROS_PCHG=m CONFIG_CHARGER_CROS_CONTROL=m +CONFIG_FUEL_GAUGE_STC3117=m CONFIG_CHARGER_BD99954=m CONFIG_CHARGER_WILCO=m CONFIG_BATTERY_SURFACE=m @@ -5334,10 +5430,13 @@ CONFIG_SENSORS_ASUS_ROG_RYUJIN=m CONFIG_SENSORS_AXI_FAN_CONTROL=m CONFIG_SENSORS_K8TEMP=m CONFIG_SENSORS_K10TEMP=m +CONFIG_SENSORS_KBATT=m +CONFIG_SENSORS_KFAN=m CONFIG_SENSORS_FAM15H_POWER=m CONFIG_SENSORS_APPLESMC=m CONFIG_SENSORS_ASB100=m CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CGBC=m CONFIG_SENSORS_CHIPCAP2=m CONFIG_SENSORS_CORSAIR_CPRO=m CONFIG_SENSORS_CORSAIR_PSU=m @@ -5363,11 +5462,13 @@ CONFIG_SENSORS_G760A=m CONFIG_SENSORS_G762=m CONFIG_SENSORS_HIH6130=m CONFIG_SENSORS_HS3001=m +CONFIG_SENSORS_HTU31=m CONFIG_SENSORS_IBMAEM=m CONFIG_SENSORS_IBMPEX=m CONFIG_SENSORS_IIO_HWMON=m CONFIG_SENSORS_I5500=m CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_ISL28022=m CONFIG_SENSORS_IT87=m CONFIG_SENSORS_JC42=m CONFIG_SENSORS_POWERZ=m @@ -5404,6 +5505,7 @@ CONFIG_SENSORS_MAX6639=m CONFIG_SENSORS_MAX6650=m CONFIG_SENSORS_MAX6697=m CONFIG_SENSORS_MAX31790=m +CONFIG_SENSORS_MAX77705=m CONFIG_SENSORS_MC34VR500=m CONFIG_SENSORS_MCP3021=m CONFIG_SENSORS_MLXREG_FAN=m @@ -5435,6 +5537,7 @@ CONFIG_SENSORS_NCT6683=m CONFIG_SENSORS_NCT6775_CORE=m CONFIG_SENSORS_NCT6775=m CONFIG_SENSORS_NCT6775_I2C=m +CONFIG_SENSORS_NCT7363=m CONFIG_SENSORS_NCT7802=m CONFIG_SENSORS_NCT7904=m CONFIG_SENSORS_NPCM7XX=m @@ -5443,7 +5546,6 @@ CONFIG_SENSORS_NZXT_KRAKEN3=m CONFIG_SENSORS_NZXT_SMART2=m CONFIG_SENSORS_OCC_P8_I2C=m CONFIG_SENSORS_OCC=m -CONFIG_SENSORS_OXP=m CONFIG_SENSORS_PCF8591=m CONFIG_PMBUS=m CONFIG_SENSORS_PMBUS=m @@ -5453,10 +5555,12 @@ CONFIG_SENSORS_ADM1275=m CONFIG_SENSORS_ADP1050=m CONFIG_SENSORS_BEL_PFE=m CONFIG_SENSORS_BPA_RS600=m +CONFIG_SENSORS_CRPS=m CONFIG_SENSORS_DELTA_AHE50DC_FAN=m CONFIG_SENSORS_FSP_3Y=m CONFIG_SENSORS_IBM_CFFPS=m CONFIG_SENSORS_DPS920AB=m +CONFIG_SENSORS_INA233=m CONFIG_SENSORS_INSPUR_IPSPS=m CONFIG_SENSORS_IR35221=m CONFIG_SENSORS_IR36021=m @@ -5466,6 +5570,8 @@ CONFIG_SENSORS_IRPS5401=m CONFIG_SENSORS_ISL68137=m CONFIG_SENSORS_LM25066=m CONFIG_SENSORS_LM25066_REGULATOR=y +CONFIG_SENSORS_LT3074=m +CONFIG_SENSORS_LT3074_REGULATOR=m CONFIG_SENSORS_LT7182S=m CONFIG_SENSORS_LTC2978=m # CONFIG_SENSORS_LTC2978_REGULATOR is not set @@ -5501,6 +5607,8 @@ CONFIG_SENSORS_Q54SJ108A2=m CONFIG_SENSORS_STPDDC60=m CONFIG_SENSORS_TDA38640=m CONFIG_SENSORS_TDA38640_REGULATOR=y +CONFIG_SENSORS_TPS25990=m +CONFIG_SENSORS_TPS25990_REGULATOR=y CONFIG_SENSORS_TPS40422=m CONFIG_SENSORS_TPS53679=m CONFIG_SENSORS_TPS546D24=m @@ -5513,8 +5621,8 @@ CONFIG_SENSORS_XDPE122_REGULATOR=y CONFIG_SENSORS_ZL6100=m CONFIG_SENSORS_PT5161L=m CONFIG_SENSORS_PWM_FAN=m +CONFIG_SENSORS_QNAP_MCU_HWMON=m CONFIG_SENSORS_SBTSI=m -CONFIG_SENSORS_SBRMI=m CONFIG_SENSORS_SHT15=m CONFIG_SENSORS_SHT21=m CONFIG_SENSORS_SHT3x=m @@ -5601,6 +5709,7 @@ CONFIG_THERMAL_GOV_BANG_BANG=y CONFIG_THERMAL_GOV_USER_SPACE=y CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y CONFIG_DEVFREQ_THERMAL=y +# CONFIG_PCIE_THERMAL is not set # CONFIG_THERMAL_EMULATION is not set # @@ -5658,6 +5767,7 @@ CONFIG_DA9055_WATCHDOG=m CONFIG_DA9063_WATCHDOG=m CONFIG_DA9062_WATCHDOG=m CONFIG_LENOVO_SE10_WDT=m +CONFIG_LENOVO_SE30_WDT=m CONFIG_MENF21BMC_WATCHDOG=m CONFIG_MENZ069_WATCHDOG=m CONFIG_WDAT_WDT=m @@ -5677,6 +5787,7 @@ CONFIG_ADVANTECH_WDT=m CONFIG_ADVANTECH_EC_WDT=m CONFIG_ALIM1535_WDT=m CONFIG_ALIM7101_WDT=m +CONFIG_CGBC_WDT=m CONFIG_EBC_C384_WDT=m CONFIG_EXAR_WDT=m CONFIG_F71808E_WDT=m @@ -5688,6 +5799,7 @@ CONFIG_IBMASR=m CONFIG_WAFER_WDT=m CONFIG_I6300ESB_WDT=m CONFIG_IE6XX_WDT=m +CONFIG_INTEL_OC_WATCHDOG=m CONFIG_ITCO_WDT=m CONFIG_ITCO_VENDOR_SUPPORT=y CONFIG_IT8712F_WDT=m @@ -5699,7 +5811,6 @@ CONFIG_SC1200_WDT=m CONFIG_PC87413_WDT=m CONFIG_NV_TCO=m CONFIG_60XX_WDT=m -CONFIG_CPU5_WDT=m CONFIG_SMSC_SCH311X_WDT=m CONFIG_SMSC37B787_WDT=m CONFIG_TQMX86_WDT=m @@ -5763,6 +5874,7 @@ CONFIG_MFD_BCM590XX=m CONFIG_MFD_BD9571MWV=m CONFIG_MFD_AXP20X=m CONFIG_MFD_AXP20X_I2C=m +CONFIG_MFD_CGBC=m CONFIG_MFD_CROS_EC_DEV=m CONFIG_MFD_CS42L43=m CONFIG_MFD_CS42L43_I2C=m @@ -5809,6 +5921,7 @@ CONFIG_MFD_88PM860X=y CONFIG_MFD_MAX14577=m CONFIG_MFD_MAX77541=m CONFIG_MFD_MAX77693=m +CONFIG_MFD_MAX77705=m CONFIG_MFD_MAX77843=y CONFIG_MFD_MAX8907=m CONFIG_MFD_MAX8925=y @@ -5822,9 +5935,6 @@ CONFIG_MFD_OCELOT=m CONFIG_EZX_PCAP=y CONFIG_MFD_VIPERBOARD=m CONFIG_MFD_RETU=m -CONFIG_MFD_PCF50633=m -CONFIG_PCF50633_ADC=m -CONFIG_PCF50633_GPIO=m CONFIG_MFD_SY7636A=m CONFIG_MFD_RDC321X=m CONFIG_MFD_RT4831=m @@ -5887,6 +5997,8 @@ CONFIG_RAVE_SP_CORE=m CONFIG_MFD_INTEL_M10_BMC_CORE=m CONFIG_MFD_INTEL_M10_BMC_SPI=m CONFIG_MFD_INTEL_M10_BMC_PMCI=m +CONFIG_MFD_QNAP_MCU=m +CONFIG_MFD_UPBOARD_FPGA=m # end of Multifunction device drivers CONFIG_REGULATOR=y @@ -5900,6 +6012,7 @@ CONFIG_REGULATOR_88PM800=m CONFIG_REGULATOR_88PM8607=m CONFIG_REGULATOR_ACT8865=m CONFIG_REGULATOR_AD5398=m +CONFIG_REGULATOR_ADP5055=m CONFIG_REGULATOR_AAT2870=m CONFIG_REGULATOR_ARIZONA_LDO1=m CONFIG_REGULATOR_ARIZONA_MICSUPP=m @@ -5960,8 +6073,8 @@ CONFIG_REGULATOR_MT6370=m CONFIG_REGULATOR_MT6397=m CONFIG_REGULATOR_PALMAS=m CONFIG_REGULATOR_PCA9450=m +CONFIG_REGULATOR_PF9453=m CONFIG_REGULATOR_PCAP=m -CONFIG_REGULATOR_PCF50633=m CONFIG_REGULATOR_PV88060=m CONFIG_REGULATOR_PV88080=m CONFIG_REGULATOR_PV88090=m @@ -6051,6 +6164,7 @@ CONFIG_MEDIA_CEC_RC=y # CONFIG_CEC_PIN_ERROR_INJ is not set CONFIG_MEDIA_CEC_SUPPORT=y CONFIG_CEC_CH7322=m +CONFIG_CEC_NXP_TDA9950=m CONFIG_CEC_CROS_EC=m CONFIG_CEC_GPIO=m CONFIG_CEC_SECO=m @@ -6367,7 +6481,6 @@ CONFIG_I2C_SI470X=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m -CONFIG_RADIO_WL128X=m CONFIG_MEDIA_PLATFORM_DRIVERS=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_DVB_PLATFORM_DRIVERS=y @@ -6440,6 +6553,7 @@ CONFIG_VIDEO_CAFE_CCIC=m # # Raspberry Pi media platform drivers # +CONFIG_VIDEO_RP1_CFE=m # # Renesas media platform drivers @@ -6487,6 +6601,7 @@ CONFIG_VIDEO_VICODEC=m CONFIG_VIDEO_VIMC=m CONFIG_VIDEO_VIVID=m CONFIG_VIDEO_VIVID_CEC=y +CONFIG_VIDEO_VIVID_OSD=y CONFIG_VIDEO_VIVID_MAX_DEVS=64 CONFIG_VIDEO_VISL=m # CONFIG_VISL_DEBUGFS is not set @@ -6569,6 +6684,8 @@ CONFIG_VIDEO_MT9V111=m CONFIG_VIDEO_OG01A1B=m CONFIG_VIDEO_OV01A10=m CONFIG_VIDEO_OV02A10=m +CONFIG_VIDEO_OV02E10=m +CONFIG_VIDEO_OV02C10=m CONFIG_VIDEO_OV08D10=m CONFIG_VIDEO_OV08X40=m CONFIG_VIDEO_OV13858=m @@ -6604,6 +6721,8 @@ CONFIG_VIDEO_RJ54N1=m CONFIG_VIDEO_S5C73M3=m CONFIG_VIDEO_S5K5BAF=m CONFIG_VIDEO_S5K6A3=m +CONFIG_VIDEO_VD55G1=m +CONFIG_VIDEO_VD56G3=m CONFIG_VIDEO_CCS=m CONFIG_VIDEO_ET8EK8=m @@ -6903,29 +7022,56 @@ CONFIG_AGP_SIS=m CONFIG_AGP_VIA=m CONFIG_INTEL_GTT=m CONFIG_VGA_SWITCHEROO=y +# CONFIG_NOVA_CORE is not set CONFIG_DRM=y + +# +# DRM debugging options +# +# CONFIG_DRM_DEBUG_MM is not set +# end of DRM debugging options + CONFIG_DRM_MIPI_DBI=m CONFIG_DRM_MIPI_DSI=y -# CONFIG_DRM_DEBUG_MM is not set CONFIG_DRM_KMS_HELPER=y +CONFIG_DRM_DRAW=y CONFIG_DRM_PANIC=y CONFIG_DRM_PANIC_FOREGROUND_COLOR=0xffffff CONFIG_DRM_PANIC_BACKGROUND_COLOR=0x0000aa # CONFIG_DRM_PANIC_DEBUG is not set -CONFIG_DRM_PANIC_SCREEN="kmsg" +CONFIG_DRM_PANIC_SCREEN="qr_code" +CONFIG_DRM_PANIC_SCREEN_QR_CODE=y +CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL="https://panic.archlinux.org/panic_report#" +CONFIG_DRM_PANIC_SCREEN_QR_VERSION=40 +CONFIG_DRM_CLIENT=y +CONFIG_DRM_CLIENT_LIB=y +CONFIG_DRM_CLIENT_SELECTION=y +CONFIG_DRM_CLIENT_SETUP=y + +# +# Supported DRM clients +# CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_FBDEV_OVERALLOC=100 +CONFIG_DRM_CLIENT_LOG=y +CONFIG_DRM_CLIENT_DEFAULT_FBDEV=y +# CONFIG_DRM_CLIENT_DEFAULT_LOG is not set +CONFIG_DRM_CLIENT_DEFAULT="fbdev" +# end of Supported DRM clients + CONFIG_DRM_LOAD_EDID_FIRMWARE=y CONFIG_DRM_DISPLAY_HELPER=m CONFIG_DRM_DISPLAY_DP_AUX_CEC=y CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV=y CONFIG_DRM_DISPLAY_DP_HELPER=y CONFIG_DRM_DISPLAY_DP_TUNNEL=y +CONFIG_DRM_DISPLAY_DSC_HELPER=y CONFIG_DRM_DISPLAY_HDCP_HELPER=y CONFIG_DRM_DISPLAY_HDMI_HELPER=y CONFIG_DRM_TTM=m CONFIG_DRM_EXEC=m CONFIG_DRM_GPUVM=m +CONFIG_DRM_GPUSVM=m CONFIG_DRM_BUDDY=m CONFIG_DRM_VRAM_HELPER=m CONFIG_DRM_TTM_HELPER=m @@ -6935,13 +7081,11 @@ CONFIG_DRM_SUBALLOC_HELPER=m CONFIG_DRM_SCHED=m # -# I2C encoder or helper chips +# Drivers for system framebuffers # -CONFIG_DRM_I2C_CH7006=m -CONFIG_DRM_I2C_SIL164=m -CONFIG_DRM_I2C_NXP_TDA998X=m -CONFIG_DRM_I2C_NXP_TDA9950=m -# end of I2C encoder or helper chips +CONFIG_DRM_SYSFB_HELPER=y +CONFIG_DRM_SIMPLEDRM=y +# end of Drivers for system framebuffers # # ARM devices @@ -6981,6 +7125,9 @@ CONFIG_NOUVEAU_DEBUG_DEFAULT=3 CONFIG_DRM_NOUVEAU_BACKLIGHT=y CONFIG_DRM_NOUVEAU_SVM=y CONFIG_DRM_NOUVEAU_GSP_DEFAULT=y +CONFIG_DRM_NOUVEAU_CH7006=m +CONFIG_DRM_NOUVEAU_SIL164=m +# CONFIG_DRM_NOVA is not set CONFIG_DRM_I915=m CONFIG_DRM_I915_FORCE_PROBE="*" CONFIG_DRM_I915_CAPTURE_ERROR=y @@ -7001,6 +7148,9 @@ CONFIG_DRM_I915_TIMESLICE_DURATION=1 CONFIG_DRM_I915_GVT=y CONFIG_DRM_XE=m CONFIG_DRM_XE_DISPLAY=y +CONFIG_DRM_XE_DP_TUNNEL=y +CONFIG_DRM_XE_GPUSVM=y +CONFIG_DRM_XE_DEVMEM_MIRROR=y CONFIG_DRM_XE_FORCE_PROBE="" CONFIG_DRM_XE_JOB_TIMEOUT_MAX=10000 CONFIG_DRM_XE_JOB_TIMEOUT_MIN=1 @@ -7039,16 +7189,18 @@ CONFIG_DRM_PANEL_BRIDGE=y # # Display Interface Bridges # +CONFIG_DRM_I2C_NXP_TDA998X=m CONFIG_DRM_ANALOGIX_ANX78XX=m CONFIG_DRM_ANALOGIX_DP=m # end of Display Interface Bridges # CONFIG_DRM_ETNAVIV is not set +CONFIG_DRM_HISI_HIBMC=m +CONFIG_DRM_APPLETBDRM=m CONFIG_DRM_BOCHS=m CONFIG_DRM_CIRRUS_QEMU=m CONFIG_DRM_GM12U320=m CONFIG_DRM_PANEL_MIPI_DBI=m -CONFIG_DRM_SIMPLEDRM=y CONFIG_TINYDRM_HX8357D=m CONFIG_TINYDRM_ILI9163=m CONFIG_TINYDRM_ILI9225=m @@ -7056,16 +7208,19 @@ CONFIG_TINYDRM_ILI9341=m CONFIG_TINYDRM_ILI9486=m CONFIG_TINYDRM_MI0283QT=m CONFIG_TINYDRM_REPAPER=m -CONFIG_TINYDRM_ST7586=m -CONFIG_TINYDRM_ST7735R=m +CONFIG_TINYDRM_SHARP_MEMORY=m CONFIG_DRM_XEN=y CONFIG_DRM_XEN_FRONTEND=m CONFIG_DRM_VBOXVIDEO=m CONFIG_DRM_GUD=m +CONFIG_DRM_ST7571_I2C=m +CONFIG_DRM_ST7586=m +CONFIG_DRM_ST7735R=m CONFIG_DRM_SSD130X=m CONFIG_DRM_SSD130X_I2C=m CONFIG_DRM_SSD130X_SPI=m CONFIG_DRM_HYPERV=m +CONFIG_DRM_PANEL_BACKLIGHT_QUIRKS=m CONFIG_DRM_PRIVACY_SCREEN=y CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y @@ -7176,7 +7331,6 @@ CONFIG_BACKLIGHT_ADP5520=m CONFIG_BACKLIGHT_ADP8860=m CONFIG_BACKLIGHT_ADP8870=m CONFIG_BACKLIGHT_88PM860X=m -CONFIG_BACKLIGHT_PCF50633=m CONFIG_BACKLIGHT_AAT2870=m CONFIG_BACKLIGHT_LM3509=m CONFIG_BACKLIGHT_LM3630A=m @@ -7215,8 +7369,10 @@ CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y # end of Graphics support CONFIG_DRM_ACCEL=y +CONFIG_DRM_ACCEL_AMDXDNA=m CONFIG_DRM_ACCEL_HABANALABS=m CONFIG_DRM_ACCEL_IVPU=m +# CONFIG_DRM_ACCEL_IVPU_DEBUG is not set CONFIG_DRM_ACCEL_QAIC=m CONFIG_SOUND=m CONFIG_SOUND_OSS_CORE=y @@ -7366,6 +7522,7 @@ CONFIG_SND_YMFPCI=m CONFIG_SND_HDA=m CONFIG_SND_HDA_GENERIC_LEDS=y CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_ACPI=m CONFIG_SND_HDA_HWDEP=y CONFIG_SND_HDA_RECONFIG=y CONFIG_SND_HDA_INPUT_BEEP=y @@ -7373,14 +7530,15 @@ CONFIG_SND_HDA_INPUT_BEEP_MODE=0 CONFIG_SND_HDA_PATCH_LOADER=y CONFIG_SND_HDA_CIRRUS_SCODEC=m CONFIG_SND_HDA_SCODEC_CS35L41=m -CONFIG_SND_HDA_CS_DSP_CONTROLS=m CONFIG_SND_HDA_SCODEC_COMPONENT=m CONFIG_SND_HDA_SCODEC_CS35L41_I2C=m CONFIG_SND_HDA_SCODEC_CS35L41_SPI=m CONFIG_SND_HDA_SCODEC_CS35L56=m CONFIG_SND_HDA_SCODEC_CS35L56_I2C=m CONFIG_SND_HDA_SCODEC_CS35L56_SPI=m +CONFIG_SND_HDA_SCODEC_TAS2781=m CONFIG_SND_HDA_SCODEC_TAS2781_I2C=m +CONFIG_SND_HDA_SCODEC_TAS2781_SPI=m CONFIG_SND_HDA_CODEC_REALTEK=m CONFIG_SND_HDA_CODEC_ANALOG=m CONFIG_SND_HDA_CODEC_SIGMATEL=m @@ -7424,6 +7582,7 @@ CONFIG_SND_USB_US122L=m CONFIG_SND_USB_6FIRE=m CONFIG_SND_USB_HIFACE=m CONFIG_SND_BCD2000=m +CONFIG_SND_USB_AUDIO_QMI=m CONFIG_SND_USB_LINE6=m CONFIG_SND_USB_POD=m CONFIG_SND_USB_PODHD=m @@ -7449,6 +7608,7 @@ CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y CONFIG_SND_SOC_COMPRESS=y CONFIG_SND_SOC_TOPOLOGY=y CONFIG_SND_SOC_ACPI=m +CONFIG_SND_SOC_USB=m CONFIG_SND_SOC_ADI=m CONFIG_SND_SOC_ADI_AXI_I2S=m CONFIG_SND_SOC_ADI_AXI_SPDIF=m @@ -7470,6 +7630,7 @@ CONFIG_SND_SOC_ACPI_AMD_MATCH=m CONFIG_SND_SOC_AMD_ACP_PDM=m CONFIG_SND_SOC_AMD_ACP_LEGACY_COMMON=m CONFIG_SND_SOC_AMD_ACP_I2S=m +CONFIG_SND_SOC_AMD_ACPI_MACH=m CONFIG_SND_SOC_AMD_ACP_PCM=m CONFIG_SND_SOC_AMD_ACP_PCI=m CONFIG_SND_AMD_ASOC_RENOIR=m @@ -7479,7 +7640,9 @@ CONFIG_SND_AMD_ASOC_ACP70=m CONFIG_SND_SOC_AMD_MACH_COMMON=m CONFIG_SND_SOC_AMD_LEGACY_MACH=m CONFIG_SND_SOC_AMD_SOF_MACH=m +CONFIG_SND_SOC_AMD_SDW_MACH_COMMON=m CONFIG_SND_SOC_AMD_SOF_SDW_MACH=m +CONFIG_SND_SOC_AMD_LEGACY_SDW_MACH=m CONFIG_SND_AMD_SOUNDWIRE_ACPI=m CONFIG_SND_SOC_AMD_RPL_ACP6x=m CONFIG_SND_SOC_AMD_ACP63_TOPLEVEL=m @@ -7513,6 +7676,12 @@ CONFIG_SND_SOC_FSL_UTILS=m CONFIG_SND_SOC_CHV3_I2S=m CONFIG_SND_I2S_HI6210_I2S=m + +# +# SoC Audio for Loongson CPUs +# +# end of SoC Audio for Loongson CPUs + CONFIG_SND_SOC_IMG=y CONFIG_SND_SOC_IMG_I2S_IN=m CONFIG_SND_SOC_IMG_I2S_OUT=m @@ -7526,6 +7695,7 @@ CONFIG_SND_SST_ATOM_HIFI2_PLATFORM=m CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI=m CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI=m CONFIG_SND_SOC_ACPI_INTEL_MATCH=m +CONFIG_SND_SOC_ACPI_INTEL_SDCA_QUIRKS=m CONFIG_SND_SOC_INTEL_AVS=m # @@ -7535,6 +7705,7 @@ CONFIG_SND_SOC_INTEL_AVS=m # # Available DSP configurations # +# CONFIG_SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE is not set CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219=m CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC=m CONFIG_SND_SOC_INTEL_AVS_MACH_ES8336=m @@ -7544,6 +7715,7 @@ CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927=m CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A=m CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373=m CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825=m +CONFIG_SND_SOC_INTEL_AVS_MACH_PCM3168A=m CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE=m CONFIG_SND_SOC_INTEL_AVS_MACH_RT274=m CONFIG_SND_SOC_INTEL_AVS_MACH_RT286=m @@ -7593,6 +7765,8 @@ CONFIG_SND_SOC_INTEL_SOF_SSP_AMP_MACH=m CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH=m CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH=m CONFIG_SND_SOC_MTK_BTCVSD=m +CONFIG_SND_SOC_SDCA=m +CONFIG_SND_SOC_SDCA_OPTIONAL=m CONFIG_SND_SOC_SOF_TOPLEVEL=y CONFIG_SND_SOC_SOF_PCI_DEV=m CONFIG_SND_SOC_SOF_PCI=m @@ -7648,6 +7822,7 @@ CONFIG_SND_SOC_SOF_HDA_GENERIC=m CONFIG_SND_SOC_SOF_HDA_MLINK=m CONFIG_SND_SOC_SOF_HDA_LINK=y CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC=y +CONFIG_SND_SOF_SOF_HDA_SDW_BPT=m CONFIG_SND_SOC_SOF_HDA_LINK_BASELINE=m CONFIG_SND_SOC_SOF_HDA=m CONFIG_SND_SOC_SOF_HDA_PROBES=m @@ -7676,6 +7851,7 @@ CONFIG_SND_SOC_ADAU_UTILS=m CONFIG_SND_SOC_ADAU1372=m CONFIG_SND_SOC_ADAU1372_I2C=m CONFIG_SND_SOC_ADAU1372_SPI=m +CONFIG_SND_SOC_ADAU1373=m CONFIG_SND_SOC_ADAU1701=m CONFIG_SND_SOC_ADAU17X1=m CONFIG_SND_SOC_ADAU1761=m @@ -7700,7 +7876,9 @@ CONFIG_SND_SOC_AUDIO_IIO_AUX=m CONFIG_SND_SOC_AW8738=m CONFIG_SND_SOC_AW88395_LIB=m CONFIG_SND_SOC_AW88395=m +CONFIG_SND_SOC_AW88166=m CONFIG_SND_SOC_AW88261=m +CONFIG_SND_SOC_AW88081=m CONFIG_SND_SOC_AW87390=m CONFIG_SND_SOC_AW88399=m CONFIG_SND_SOC_BD28623=m @@ -7737,6 +7915,7 @@ CONFIG_SND_SOC_CS42L52=m CONFIG_SND_SOC_CS42L56=m CONFIG_SND_SOC_CS42L73=m CONFIG_SND_SOC_CS42L83=m +CONFIG_SND_SOC_CS42L84=m CONFIG_SND_SOC_CS4234=m CONFIG_SND_SOC_CS4265=m CONFIG_SND_SOC_CS4270=m @@ -7748,6 +7927,7 @@ CONFIG_SND_SOC_CS42XX8_I2C=m CONFIG_SND_SOC_CS43130=m CONFIG_SND_SOC_CS4341=m CONFIG_SND_SOC_CS4349=m +CONFIG_SND_SOC_CS48L32=m CONFIG_SND_SOC_CS53L30=m CONFIG_SND_SOC_CS530X=m CONFIG_SND_SOC_CS530X_I2C=m @@ -7761,10 +7941,13 @@ CONFIG_SND_SOC_ES7241=m CONFIG_SND_SOC_ES83XX_DSM_COMMON=m CONFIG_SND_SOC_ES8311=m CONFIG_SND_SOC_ES8316=m +CONFIG_SND_SOC_ES8323=m CONFIG_SND_SOC_ES8326=m CONFIG_SND_SOC_ES8328=m CONFIG_SND_SOC_ES8328_I2C=m CONFIG_SND_SOC_ES8328_SPI=m +CONFIG_SND_SOC_ES8375=m +CONFIG_SND_SOC_ES8389=m CONFIG_SND_SOC_GTM601=m CONFIG_SND_SOC_HDAC_HDA=m CONFIG_SND_SOC_HDA=m @@ -7808,6 +7991,7 @@ CONFIG_SND_SOC_PCM512x_SPI=m CONFIG_SND_SOC_PCM6240=m CONFIG_SND_SOC_PEB2466=m CONFIG_SND_SOC_RL6231=m +CONFIG_SND_SOC_RT_SDW_COMMON=m CONFIG_SND_SOC_RL6347A=m CONFIG_SND_SOC_RT274=m CONFIG_SND_SOC_RT286=m @@ -7845,11 +8029,14 @@ CONFIG_SND_SOC_RT711_SDW=m CONFIG_SND_SOC_RT711_SDCA_SDW=m CONFIG_SND_SOC_RT712_SDCA_SDW=m CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW=m +CONFIG_SND_SOC_RT721_SDCA_SDW=m CONFIG_SND_SOC_RT722_SDCA_SDW=m CONFIG_SND_SOC_RT715=m CONFIG_SND_SOC_RT715_SDW=m CONFIG_SND_SOC_RT715_SDCA_SDW=m CONFIG_SND_SOC_RT9120=m +CONFIG_SND_SOC_RT9123=m +CONFIG_SND_SOC_RT9123P=m CONFIG_SND_SOC_RTQ9128=m # CONFIG_SND_SOC_SDW_MOCKUP is not set CONFIG_SND_SOC_SGTL5000=m @@ -7860,6 +8047,7 @@ CONFIG_SND_SOC_SIGMADSP_REGMAP=m CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m CONFIG_SND_SOC_SIMPLE_MUX=m CONFIG_SND_SOC_SMA1303=m +CONFIG_SND_SOC_SMA1307=m CONFIG_SND_SOC_SPDIF=m CONFIG_SND_SOC_SRC4XXX_I2C=m CONFIG_SND_SOC_SRC4XXX=m @@ -7878,6 +8066,7 @@ CONFIG_SND_SOC_TAS2764=m CONFIG_SND_SOC_TAS2770=m CONFIG_SND_SOC_TAS2780=m CONFIG_SND_SOC_TAS2781_COMLIB=m +CONFIG_SND_SOC_TAS2781_COMLIB_I2C=m CONFIG_SND_SOC_TAS2781_FMWLIB=m CONFIG_SND_SOC_TAS2781_I2C=m CONFIG_SND_SOC_TAS5086=m @@ -7904,6 +8093,7 @@ CONFIG_SND_SOC_TS3A227E=m CONFIG_SND_SOC_TSCS42XX=m CONFIG_SND_SOC_TSCS454=m CONFIG_SND_SOC_UDA1334=m +CONFIG_SND_SOC_UDA1342=m CONFIG_SND_SOC_WCD_CLASSH=m CONFIG_SND_SOC_WCD9335=m CONFIG_SND_SOC_WCD_MBHC=m @@ -7943,6 +8133,7 @@ CONFIG_SND_SOC_WM8962=m CONFIG_SND_SOC_WM8974=m CONFIG_SND_SOC_WM8978=m CONFIG_SND_SOC_WM8985=m +CONFIG_SND_SOC_WM8998=m CONFIG_SND_SOC_WSA881X=m CONFIG_SND_SOC_WSA883X=m CONFIG_SND_SOC_WSA884X=m @@ -7959,6 +8150,9 @@ CONFIG_SND_SOC_NAU8821=m CONFIG_SND_SOC_NAU8822=m CONFIG_SND_SOC_NAU8824=m CONFIG_SND_SOC_NAU8825=m +CONFIG_SND_SOC_NTPFW=m +CONFIG_SND_SOC_NTP8918=m +CONFIG_SND_SOC_NTP8835=m CONFIG_SND_SOC_TPA6130A2=m CONFIG_SND_SOC_LPASS_MACRO_COMMON=m CONFIG_SND_SOC_LPASS_WSA_MACRO=m @@ -7981,7 +8175,7 @@ CONFIG_HID=y CONFIG_HID_BATTERY_STRENGTH=y CONFIG_HIDRAW=y CONFIG_UHID=m -CONFIG_HID_GENERIC=m +CONFIG_HID_GENERIC=y # # Special HID drivers @@ -7992,6 +8186,8 @@ CONFIG_HID_ACRUX=m CONFIG_HID_ACRUX_FF=y CONFIG_HID_APPLE=m CONFIG_HID_APPLEIR=m +CONFIG_HID_APPLETB_BL=m +CONFIG_HID_APPLETB_KBD=m CONFIG_HID_ASUS=m CONFIG_HID_AUREAL=m CONFIG_HID_BELKIN=m @@ -8029,6 +8225,7 @@ CONFIG_HID_VIVALDI=m CONFIG_HID_GT683R=m CONFIG_HID_KEYTOUCH=m CONFIG_HID_KYE=m +CONFIG_HID_KYSONA=m CONFIG_HID_UCLOGIC=m CONFIG_HID_WALTOP=m CONFIG_HID_VIEWSONIC=m @@ -8109,6 +8306,7 @@ CONFIG_HID_THRUSTMASTER=m CONFIG_THRUSTMASTER_FF=y CONFIG_HID_UDRAW_PS3=m CONFIG_HID_U2FZERO=m +CONFIG_HID_UNIVERSAL_PIDFF=m CONFIG_HID_WACOM=m CONFIG_HID_WIIMOTE=m CONFIG_HID_WINWING=m @@ -8129,14 +8327,6 @@ CONFIG_HID_MCP2221=m CONFIG_HID_BPF=y # end of HID-BPF support -# -# USB HID support -# -CONFIG_USB_HID=m -CONFIG_HID_PID=y -CONFIG_USB_HIDDEV=y -# end of USB HID support - CONFIG_I2C_HID=m CONFIG_I2C_HID_ACPI=m CONFIG_I2C_HID_OF=m @@ -8163,6 +8353,23 @@ CONFIG_SURFACE_KBD=m # end of Surface System Aggregator Module HID support CONFIG_SURFACE_HID_CORE=m + +# +# Intel THC HID Support +# +CONFIG_INTEL_THC_HID=m +CONFIG_INTEL_QUICKSPI=m +CONFIG_INTEL_QUICKI2C=m +# end of Intel THC HID Support + +# +# USB HID support +# +CONFIG_USB_HID=y +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y +# end of USB HID support + CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_USB_SUPPORT=y CONFIG_USB_COMMON=y @@ -8197,6 +8404,7 @@ CONFIG_USB_XHCI_DBGCAP=y CONFIG_USB_XHCI_PCI=y CONFIG_USB_XHCI_PCI_RENESAS=m CONFIG_USB_XHCI_PLATFORM=m +CONFIG_USB_XHCI_SIDEBAND=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y @@ -8228,11 +8436,7 @@ CONFIG_USB_WDM=m CONFIG_USB_TMC=m # -# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may -# - -# -# also be needed; see USB_STORAGE Help for more info +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; see USB_STORAGE Help for more info # CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set @@ -8448,14 +8652,10 @@ CONFIG_U_SERIAL_CONSOLE=y CONFIG_USB_GR_UDC=m CONFIG_USB_R8A66597=m CONFIG_USB_PXA27X=m -CONFIG_USB_MV_UDC=m -CONFIG_USB_MV_U3D=m CONFIG_USB_SNP_CORE=m CONFIG_USB_M66592=m CONFIG_USB_BDC_UDC=m CONFIG_USB_AMD5536UDC=m -CONFIG_USB_NET2272=m -# CONFIG_USB_NET2272_DMA is not set CONFIG_USB_NET2280=m CONFIG_USB_GOKU=m CONFIG_USB_EG20T=m @@ -8559,6 +8759,7 @@ CONFIG_TYPEC_UCSI=m CONFIG_UCSI_CCG=m CONFIG_UCSI_ACPI=m CONFIG_UCSI_STM32G0=m +CONFIG_CROS_EC_UCSI=m CONFIG_TYPEC_TPS6598X=m CONFIG_TYPEC_ANX7411=m CONFIG_TYPEC_RT1719=m @@ -8575,7 +8776,9 @@ CONFIG_TYPEC_MUX_PI3USB30532=m CONFIG_TYPEC_MUX_INTEL_PMC=m CONFIG_TYPEC_MUX_IT5205=m CONFIG_TYPEC_MUX_NB7VPQ904M=m +CONFIG_TYPEC_MUX_PS883X=m CONFIG_TYPEC_MUX_PTN36502=m +CONFIG_TYPEC_MUX_TUSB1046=m CONFIG_TYPEC_MUX_WCD939X_USBSS=m # end of USB Type-C Multiplexer/DeMultiplexer Switch support @@ -8584,6 +8787,7 @@ CONFIG_TYPEC_MUX_WCD939X_USBSS=m # CONFIG_TYPEC_DP_ALTMODE=m CONFIG_TYPEC_NVIDIA_ALTMODE=m +CONFIG_TYPEC_TBT_ALTMODE=m # end of USB Type-C Alternate Mode drivers CONFIG_USB_ROLE_SWITCH=m @@ -8601,6 +8805,7 @@ CONFIG_MMC_CRYPTO=y # CONFIG_MMC_DEBUG is not set CONFIG_MMC_SDHCI=m CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_UHS2=m CONFIG_MMC_SDHCI_PCI=m CONFIG_MMC_RICOH_MMC=y CONFIG_MMC_SDHCI_ACPI=m @@ -8679,6 +8884,7 @@ CONFIG_LEDS_PCA955X=m CONFIG_LEDS_PCA955X_GPIO=y CONFIG_LEDS_PCA963X=m CONFIG_LEDS_PCA995X=m +CONFIG_LEDS_QNAP_MCU=m CONFIG_LEDS_WM831X_STATUS=m CONFIG_LEDS_WM8350=m CONFIG_LEDS_DA903X=m @@ -8694,10 +8900,12 @@ CONFIG_LEDS_ADP5520=m CONFIG_LEDS_MC13783=m CONFIG_LEDS_TCA6507=m CONFIG_LEDS_TLC591XX=m +CONFIG_LEDS_MAX77705=m CONFIG_LEDS_MAX8997=m CONFIG_LEDS_LM355x=m CONFIG_LEDS_MENF21BMC=m CONFIG_LEDS_IS31FL319X=m +CONFIG_LEDS_UPBOARD=m # # LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) @@ -8756,7 +8964,7 @@ CONFIG_LEDS_TRIGGER_TTY=m CONFIG_LEDS_TRIGGER_INPUT_EVENTS=m # -# Simple LED drivers +# Simatic LED drivers # CONFIG_LEDS_SIEMENS_SIMATIC_IPC=m CONFIG_LEDS_SIEMENS_SIMATIC_IPC_APOLLOLAKE=m @@ -8831,6 +9039,9 @@ CONFIG_EDAC_LEGACY_SYSFS=y # CONFIG_EDAC_DEBUG is not set CONFIG_EDAC_DECODE_MCE=y CONFIG_EDAC_GHES=y +CONFIG_EDAC_SCRUB=y +CONFIG_EDAC_ECS=y +CONFIG_EDAC_MEM_REPAIR=y CONFIG_EDAC_AMD64=m CONFIG_EDAC_E752X=m CONFIG_EDAC_I82975X=m @@ -8971,7 +9182,6 @@ CONFIG_RTC_DRV_MSM6242=m CONFIG_RTC_DRV_RP5C01=m CONFIG_RTC_DRV_WM831X=m CONFIG_RTC_DRV_WM8350=m -CONFIG_RTC_DRV_PCF50633=m CONFIG_RTC_DRV_CROS_EC=m # @@ -9008,8 +9218,9 @@ CONFIG_INTEL_IOATDMA=m CONFIG_PLX_DMA=m CONFIG_XILINX_DMA=m CONFIG_XILINX_XDMA=m -CONFIG_AMD_QDMA=m +CONFIG_AMD_AE4DMA=m CONFIG_AMD_PTDMA=m +CONFIG_AMD_QDMA=m CONFIG_QCOM_HIDMA_MGMT=m CONFIG_QCOM_HIDMA=m CONFIG_DW_DMAC_CORE=y @@ -9068,7 +9279,6 @@ CONFIG_VFIO_DEBUGFS=y # VFIO support for PCI devices # CONFIG_VFIO_PCI_CORE=m -CONFIG_VFIO_PCI_MMAP=y CONFIG_VFIO_PCI_INTX=y CONFIG_VFIO_PCI=m CONFIG_VFIO_PCI_VGA=y @@ -9076,20 +9286,23 @@ CONFIG_VFIO_PCI_IGD=y CONFIG_MLX5_VFIO_PCI=m CONFIG_PDS_VFIO_PCI=m CONFIG_VIRTIO_VFIO_PCI=m +CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY=y CONFIG_QAT_VFIO_PCI=m # end of VFIO support for PCI devices CONFIG_VFIO_MDEV=m -CONFIG_IRQ_BYPASS_MANAGER=y +CONFIG_IRQ_BYPASS_MANAGER=m CONFIG_VIRT_DRIVERS=y CONFIG_VMGENID=y CONFIG_VBOXGUEST=m CONFIG_NITRO_ENCLAVES=m CONFIG_ACRN_HSM=m -CONFIG_TSM_REPORTS=m CONFIG_EFI_SECRET=m CONFIG_SEV_GUEST=m CONFIG_TDX_GUEST_DRIVER=m +CONFIG_TSM_GUEST=y +CONFIG_TSM_REPORTS=m +CONFIG_TSM_MEASUREMENTS=y CONFIG_VIRTIO_ANCHOR=y CONFIG_VIRTIO=y CONFIG_VIRTIO_PCI_LIB=y @@ -9107,6 +9320,9 @@ CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y CONFIG_VIRTIO_DMA_SHARED_BUFFER=m CONFIG_VIRTIO_DEBUG=y +CONFIG_VIRTIO_RTC=m +CONFIG_VIRTIO_RTC_PTP=y +CONFIG_VIRTIO_RTC_CLASS=y CONFIG_VDPA=m CONFIG_VDPA_SIM=m CONFIG_VDPA_SIM_NET=m @@ -9131,6 +9347,7 @@ CONFIG_VHOST_SCSI=m CONFIG_VHOST_VSOCK=m CONFIG_VHOST_VDPA=m # CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set +CONFIG_VHOST_ENABLE_FORK_OWNER_CONTROL=y # # Microsoft Hyper-V guest support @@ -9140,6 +9357,7 @@ CONFIG_HYPERV=m CONFIG_HYPERV_TIMER=y CONFIG_HYPERV_UTILS=m CONFIG_HYPERV_BALLOON=m +CONFIG_MSHV_ROOT=m # end of Microsoft Hyper-V guest support # @@ -9185,16 +9403,7 @@ CONFIG_XEN_VIRTIO=y # CONFIG_GREYBUS is not set # CONFIG_COMEDI is not set CONFIG_STAGING=y -CONFIG_RTLLIB=m -CONFIG_RTLLIB_CRYPTO_CCMP=m -CONFIG_RTLLIB_CRYPTO_TKIP=m -CONFIG_RTLLIB_CRYPTO_WEP=m -CONFIG_RTL8192E=m CONFIG_RTL8723BS=m -CONFIG_R8712U=m -CONFIG_RTS5208=m -CONFIG_VT6655=m -CONFIG_VT6656=m # # IIO staging drivers @@ -9204,7 +9413,6 @@ CONFIG_VT6656=m # Accelerometers # CONFIG_ADIS16203=m -CONFIG_ADIS16240=m # end of Accelerometers # @@ -9248,14 +9456,25 @@ CONFIG_VIDEO_IPU3_IMGU=m # StarFive media platform drivers # # CONFIG_STAGING_MEDIA_DEPRECATED is not set -CONFIG_LTE_GDM724X=m # CONFIG_FB_TFT is not set CONFIG_MOST_COMPONENTS=m CONFIG_MOST_NET=m CONFIG_MOST_VIDEO=m CONFIG_MOST_I2C=m -CONFIG_FIELDBUS_DEV=m # CONFIG_VME_BUS is not set +CONFIG_GPIB=m +CONFIG_GPIB_COMMON=m +CONFIG_GPIB_AGILENT_82350B=m +CONFIG_GPIB_AGILENT_82357A=m +CONFIG_GPIB_CEC_PCI=m +CONFIG_GPIB_NI_PCI_ISA=m +CONFIG_GPIB_CB7210=m +CONFIG_GPIB_NI_USB=m +CONFIG_GPIB_INES=m +CONFIG_GPIB_PCMCIA=y +CONFIG_GPIB_LPVO=m +CONFIG_GPIB_TMS9914=m +CONFIG_GPIB_NEC7210=m # CONFIG_GOLDFISH is not set CONFIG_CHROME_PLATFORMS=y CONFIG_CHROMEOS_ACPI=m @@ -9268,13 +9487,14 @@ CONFIG_CROS_EC_ISHTP=m CONFIG_CROS_EC_SPI=m CONFIG_CROS_EC_UART=m CONFIG_CROS_EC_LPC=m -CONFIG_CROS_EC_PROTO=y +CONFIG_CROS_EC_PROTO=m CONFIG_CROS_KBD_LED_BACKLIGHT=m CONFIG_CROS_EC_CHARDEV=m CONFIG_CROS_EC_LIGHTBAR=m CONFIG_CROS_EC_DEBUGFS=m CONFIG_CROS_EC_SENSORHUB=m CONFIG_CROS_EC_SYSFS=m +CONFIG_CROS_EC_TYPEC_ALTMODES=y CONFIG_CROS_EC_TYPEC=m CONFIG_CROS_HPS_I2C=m CONFIG_CROS_USBPD_LOGGER=m @@ -9285,8 +9505,9 @@ CONFIG_WILCO_EC=m CONFIG_WILCO_EC_DEBUGFS=m CONFIG_WILCO_EC_EVENTS=m CONFIG_WILCO_EC_TELEMETRY=m -CONFIG_CZNIC_PLATFORMS=y CONFIG_MELLANOX_PLATFORM=y +CONFIG_MLX_PLATFORM=m +CONFIG_MLXREG_DPU=m CONFIG_MLXREG_HOTPLUG=m CONFIG_MLXREG_IO=m CONFIG_MLXREG_LC=m @@ -9320,12 +9541,22 @@ CONFIG_YT2_1380=m CONFIG_ACERHDF=m CONFIG_ACER_WIRELESS=m CONFIG_ACER_WMI=m +CONFIG_AMD_HSMP=m + +# +# AMD HSMP Driver +# +CONFIG_AMD_HSMP_ACPI=m +CONFIG_AMD_HSMP_PLAT=m +# end of AMD HSMP Driver + CONFIG_AMD_PMF=m # CONFIG_AMD_PMF_DEBUG is not set CONFIG_AMD_PMC=m CONFIG_AMD_MP2_STB=y -CONFIG_AMD_HSMP=m +CONFIG_AMD_3D_VCACHE=m CONFIG_AMD_WBRF=y +CONFIG_AMD_ISP_PLATFORM=m CONFIG_ADV_SWBUTTON=m CONFIG_APPLE_GMUX=m CONFIG_ASUS_LAPTOP=m @@ -9338,6 +9569,8 @@ CONFIG_EEEPC_LAPTOP=m CONFIG_EEEPC_WMI=m CONFIG_X86_PLATFORM_DRIVERS_DELL=y CONFIG_ALIENWARE_WMI=m +CONFIG_ALIENWARE_WMI_LEGACY=y +CONFIG_ALIENWARE_WMI_WMAX=y CONFIG_DCDBAS=m CONFIG_DELL_LAPTOP=m # CONFIG_DELL_RBU is not set @@ -9366,6 +9599,7 @@ CONFIG_HP_BIOSCFG=m CONFIG_WIRELESS_HOTKEY=m CONFIG_IBM_RTL=m CONFIG_IDEAPAD_LAPTOP=m +CONFIG_LENOVO_WMI_HOTKEY_UTILITIES=m CONFIG_LENOVO_YMC=m CONFIG_SENSORS_HDAPS=m CONFIG_THINKPAD_ACPI=m @@ -9383,6 +9617,7 @@ CONFIG_INTEL_IFS=m CONFIG_INTEL_SAR_INT1092=m CONFIG_INTEL_SKL_INT3472=m CONFIG_INTEL_PMC_CORE=m +CONFIG_INTEL_PMC_SSRAM_TELEMETRY=m CONFIG_INTEL_PMT_CLASS=m CONFIG_INTEL_PMT_TELEMETRY=m CONFIG_INTEL_PMT_CRASHLOG=m @@ -9432,7 +9667,9 @@ CONFIG_MSI_LAPTOP=m CONFIG_MSI_WMI=m CONFIG_MSI_WMI_PLATFORM=m CONFIG_PCENGINES_APU2=m +CONFIG_PORTWELL_EC=m CONFIG_BARCO_P50_GPIO=m +CONFIG_SAMSUNG_GALAXYBOOK=m CONFIG_SAMSUNG_LAPTOP=m CONFIG_SAMSUNG_Q10=m CONFIG_ACPI_TOSHIBA=m @@ -9448,10 +9685,10 @@ CONFIG_SONYPI_COMPAT=y CONFIG_SYSTEM76_ACPI=m CONFIG_TOPSTAR_LAPTOP=m CONFIG_SERIAL_MULTI_INSTANTIATE=m -CONFIG_MLX_PLATFORM=m CONFIG_TOUCHSCREEN_DMI=y CONFIG_INSPUR_PLATFORM_PROFILE=m CONFIG_LENOVO_WMI_CAMERA=m +CONFIG_DASHARO_ACPI=m CONFIG_X86_ANDROID_TABLETS=m CONFIG_FW_ATTR_CLASS=m CONFIG_INTEL_IPS=m @@ -9468,6 +9705,8 @@ CONFIG_SIEMENS_SIMATIC_IPC_BATT_F7188X=m CONFIG_SILICOM_PLATFORM=m CONFIG_WINMATE_FM07_KEYS=m CONFIG_SEL3350_PLATFORM=m +CONFIG_OXP_EC=m +CONFIG_TUXEDO_NB04_WMI_AB=m CONFIG_P2SB=y CONFIG_HAVE_CLK=y CONFIG_HAVE_CLK_PREPARE=y @@ -9525,6 +9764,7 @@ CONFIG_INTEL_IOMMU_SVM=y CONFIG_INTEL_IOMMU_FLOPPY_WA=y CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON=y CONFIG_INTEL_IOMMU_PERF_EVENTS=y +CONFIG_IOMMUFD_DRIVER_CORE=y CONFIG_IOMMUFD=m CONFIG_IRQ_REMAP=y CONFIG_HYPERV_IOMMU=y @@ -9599,6 +9839,7 @@ CONFIG_WPCM450_SOC=m # # Qualcomm SoC drivers # +CONFIG_QCOM_MDT_LOADER=m CONFIG_QCOM_PMIC_PDCHARGER_ULOG=m CONFIG_QCOM_QMI_HELPERS=m # end of Qualcomm SoC drivers @@ -9766,15 +10007,19 @@ CONFIG_STK8BA50=m # # Analog to digital converters # +CONFIG_IIO_ADC_HELPER=m CONFIG_AD_SIGMA_DELTA=m CONFIG_AD4000=m +CONFIG_AD4030=m CONFIG_AD4130=m CONFIG_AD4695=m +CONFIG_AD4851=m CONFIG_AD7091R=m CONFIG_AD7091R5=m CONFIG_AD7091R8=m CONFIG_AD7124=m CONFIG_AD7173=m +CONFIG_AD7191=m CONFIG_AD7192=m CONFIG_AD7266=m CONFIG_AD7280=m @@ -9786,8 +10031,10 @@ CONFIG_AD7476=m CONFIG_AD7606=m CONFIG_AD7606_IFACE_PARALLEL=m CONFIG_AD7606_IFACE_SPI=m +CONFIG_AD7625=m CONFIG_AD7766=m CONFIG_AD7768_1=m +CONFIG_AD7779=m CONFIG_AD7780=m CONFIG_AD7791=m CONFIG_AD7793=m @@ -9803,6 +10050,7 @@ CONFIG_CC10001_ADC=m CONFIG_DA9150_GPADC=m CONFIG_DLN2_ADC=m CONFIG_ENVELOPE_DETECTOR=m +CONFIG_GEHC_PMC_ADC=m CONFIG_HI8435=m CONFIG_HX711=m CONFIG_INA2XX_ADC=m @@ -9833,28 +10081,31 @@ CONFIG_MEDIATEK_MT6370_ADC=m CONFIG_MEN_Z188_ADC=m CONFIG_MP2629_ADC=m CONFIG_NAU7802=m +CONFIG_NCT7201=m CONFIG_PAC1921=m CONFIG_PAC1934=m CONFIG_PALMAS_GPADC=m +CONFIG_ROHM_BD79124=m CONFIG_RICHTEK_RTQ6056=m CONFIG_SD_ADC_MODULATOR=m CONFIG_TI_ADC081C=m CONFIG_TI_ADC0832=m CONFIG_TI_ADC084S021=m -CONFIG_TI_ADC12138=m CONFIG_TI_ADC108S102=m +CONFIG_TI_ADC12138=m CONFIG_TI_ADC128S052=m CONFIG_TI_ADC161S626=m CONFIG_TI_ADS1015=m -CONFIG_TI_ADS1119=m -CONFIG_TI_ADS7924=m CONFIG_TI_ADS1100=m +CONFIG_TI_ADS1119=m +CONFIG_TI_ADS124S08=m CONFIG_TI_ADS1298=m +CONFIG_TI_ADS131E08=m +CONFIG_TI_ADS7138=m +CONFIG_TI_ADS7924=m CONFIG_TI_ADS7950=m CONFIG_TI_ADS8344=m CONFIG_TI_ADS8688=m -CONFIG_TI_ADS124S08=m -CONFIG_TI_ADS131E08=m CONFIG_TI_LMP92064=m CONFIG_TI_TLC4541=m CONFIG_TI_TSC2046=m @@ -9907,11 +10158,13 @@ CONFIG_ENS160=m CONFIG_ENS160_I2C=m CONFIG_ENS160_SPI=m CONFIG_IAQCORE=m +CONFIG_MHZ19B=m CONFIG_PMS7003=m CONFIG_SCD30_CORE=m CONFIG_SCD30_I2C=m CONFIG_SCD30_SERIAL=m CONFIG_SCD4X=m +CONFIG_SEN0322=m CONFIG_SENSIRION_SGP30=m CONFIG_SENSIRION_SGP40=m CONFIG_SPS30=m @@ -9954,6 +10207,9 @@ CONFIG_IIO_ST_SENSORS_CORE=m # # Digital to analog converters # +CONFIG_AD3530R=m +CONFIG_AD3552R_HS=m +CONFIG_AD3552R_LIB=m CONFIG_AD3552R=m CONFIG_AD5064=m CONFIG_AD5360=m @@ -9980,7 +10236,9 @@ CONFIG_AD5770R=m CONFIG_AD5791=m CONFIG_AD7293=m CONFIG_AD7303=m +CONFIG_AD8460=m CONFIG_AD8801=m +CONFIG_BD79703=m CONFIG_DPOT_DAC=m CONFIG_DS4424=m CONFIG_LTC1660=m @@ -10100,9 +10358,13 @@ CONFIG_ADIS16400=m CONFIG_ADIS16460=m CONFIG_ADIS16475=m CONFIG_ADIS16480=m +CONFIG_ADIS16550=m CONFIG_BMI160=m CONFIG_BMI160_I2C=m CONFIG_BMI160_SPI=m +CONFIG_BMI270=m +CONFIG_BMI270_I2C=m +CONFIG_BMI270_SPI=m CONFIG_BMI323=m CONFIG_BMI323_I2C=m CONFIG_BMI323_SPI=m @@ -10119,6 +10381,7 @@ CONFIG_INV_ICM42600_SPI=m CONFIG_INV_MPU6050_IIO=m CONFIG_INV_MPU6050_I2C=m CONFIG_INV_MPU6050_SPI=m +CONFIG_SMI240=m CONFIG_IIO_ST_LSM6DSX=m CONFIG_IIO_ST_LSM6DSX_I2C=m CONFIG_IIO_ST_LSM6DSX_SPI=m @@ -10136,8 +10399,10 @@ CONFIG_IIO_ADIS_LIB_BUFFER=y CONFIG_ACPI_ALS=m CONFIG_ADJD_S311=m CONFIG_ADUX1020=m +CONFIG_AL3000A=m CONFIG_AL3010=m CONFIG_AL3320A=m +CONFIG_APDS9160=m CONFIG_APDS9300=m CONFIG_APDS9306=m CONFIG_APDS9960=m @@ -10161,7 +10426,6 @@ CONFIG_ISL76682=m CONFIG_HID_SENSOR_ALS=m CONFIG_HID_SENSOR_PROX=m CONFIG_JSA1212=m -CONFIG_ROHM_BU27008=m CONFIG_ROHM_BU27034=m CONFIG_RPR0521=m CONFIG_SENSORS_LM3533=m @@ -10174,6 +10438,7 @@ CONFIG_MAX44009=m CONFIG_NOA1305=m CONFIG_OPT3001=m CONFIG_OPT4001=m +CONFIG_OPT4060=m CONFIG_PA12203001=m CONFIG_SI1133=m CONFIG_SI1145=m @@ -10191,6 +10456,7 @@ CONFIG_TSL4531=m CONFIG_US5182D=m CONFIG_VCNL4000=m CONFIG_VCNL4035=m +CONFIG_VEML3235=m CONFIG_VEML6030=m CONFIG_VEML6040=m CONFIG_VEML6070=m @@ -10205,6 +10471,7 @@ CONFIG_ZOPT2201=m CONFIG_AK8974=m CONFIG_AK8975=m CONFIG_AK09911=m +CONFIG_ALS31300=m CONFIG_BMC150_MAGN=m CONFIG_BMC150_MAGN_I2C=m CONFIG_BMC150_MAGN_SPI=m @@ -10220,6 +10487,7 @@ CONFIG_SENSORS_HMC5843_SPI=m CONFIG_SENSORS_RM3100=m CONFIG_SENSORS_RM3100_I2C=m CONFIG_SENSORS_RM3100_SPI=m +CONFIG_SI7210=m CONFIG_TI_TMAG5273=m CONFIG_YAMAHA_YAS530=m # end of Magnetometer sensors @@ -10388,7 +10656,7 @@ CONFIG_NTB_TRANSPORT=m CONFIG_PWM=y # CONFIG_PWM_DEBUG is not set CONFIG_PWM_CLK=m -CONFIG_PWM_CRC=m +CONFIG_PWM_CRC=y CONFIG_PWM_CROS_EC=m CONFIG_PWM_DWC_CORE=m CONFIG_PWM_DWC=m @@ -10405,7 +10673,6 @@ CONFIG_PWM_TWL_LED=m # # IRQ chip support # -CONFIG_LAN966X_OIC=m CONFIG_MADERA_IRQ=m # end of IRQ chip support @@ -10470,7 +10737,10 @@ CONFIG_USB4=m # # Android # -# CONFIG_ANDROID_BINDER_IPC is not set +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y +CONFIG_ANDROID_BINDER_DEVICES="" +# CONFIG_ANDROID_BINDER_IPC_SELFTEST is not set # end of Android CONFIG_LIBNVDIMM=m @@ -10581,20 +10851,14 @@ CONFIG_BUFFER_HEAD=y CONFIG_LEGACY_DIRECT_IO=y # CONFIG_EXT2_FS is not set # CONFIG_EXT3_FS is not set -CONFIG_EXT4_FS=m +CONFIG_EXT4_FS=y CONFIG_EXT4_USE_FOR_EXT2=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y # CONFIG_EXT4_DEBUG is not set -CONFIG_JBD2=m +CONFIG_JBD2=y # CONFIG_JBD2_DEBUG is not set -CONFIG_FS_MBCACHE=m -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -CONFIG_REISERFS_PROC_INFO=y -CONFIG_REISERFS_FS_XATTR=y -CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_REISERFS_FS_SECURITY=y +CONFIG_FS_MBCACHE=y CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y CONFIG_JFS_SECURITY=y @@ -10623,11 +10887,12 @@ CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m CONFIG_OCFS2_FS_STATS=y CONFIG_OCFS2_DEBUG_MASKLOG=y # CONFIG_OCFS2_DEBUG_FS is not set -CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS=y CONFIG_BTRFS_FS_POSIX_ACL=y # CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set # CONFIG_BTRFS_DEBUG is not set # CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_EXPERIMENTAL is not set # CONFIG_BTRFS_FS_REF_VERIFY is not set CONFIG_NILFS2_FS=m CONFIG_F2FS_FS=m @@ -10655,6 +10920,8 @@ CONFIG_BCACHEFS_LOCK_TIME_STATS=y # CONFIG_BCACHEFS_NO_LATENCY_ACCT is not set CONFIG_BCACHEFS_SIX_OPTIMISTIC_SPIN=y # CONFIG_BCACHEFS_PATH_TRACEPOINTS is not set +# CONFIG_BCACHEFS_TRANS_KMALLOC_TRACE is not set +# CONFIG_BCACHEFS_ASYNC_OBJECT_LISTS is not set CONFIG_ZONEFS_FS=m CONFIG_FS_DAX=y CONFIG_FS_DAX_PMD=y @@ -10663,7 +10930,7 @@ CONFIG_EXPORTFS=y CONFIG_EXPORTFS_BLOCK_OPS=y CONFIG_FILE_LOCKING=y CONFIG_FS_ENCRYPTION=y -CONFIG_FS_ENCRYPTION_ALGS=m +CONFIG_FS_ENCRYPTION_ALGS=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y @@ -10685,6 +10952,7 @@ CONFIG_CUSE=m CONFIG_VIRTIO_FS=y CONFIG_FUSE_DAX=y CONFIG_FUSE_PASSTHROUGH=y +CONFIG_FUSE_IO_URING=y CONFIG_OVERLAY_FS=m CONFIG_OVERLAY_FS_REDIRECT_DIR=y # CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW is not set @@ -10731,7 +10999,7 @@ CONFIG_NTFS3_FS=m # CONFIG_NTFS3_64BIT_CLUSTER is not set CONFIG_NTFS3_LZX_XPRESS=y CONFIG_NTFS3_FS_POSIX_ACL=y -# CONFIG_NTFS_FS is not set +CONFIG_NTFS_FS=m # end of DOS/FAT/EXFAT/NT Filesystems # @@ -10807,6 +11075,7 @@ CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT=y CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS=y CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_COMP_CACHE_FULL=y CONFIG_SQUASHFS_ZLIB=y CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y @@ -10821,6 +11090,8 @@ CONFIG_OMFS_FS=m # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set # CONFIG_QNX6FS_FS is not set +CONFIG_RESCTRL_FS=y +CONFIG_RESCTRL_FS_PSEUDO_LOCK=y CONFIG_ROMFS_FS=m CONFIG_ROMFS_BACKED_BY_BLOCK=y # CONFIG_ROMFS_BACKED_BY_MTD is not set @@ -10838,7 +11109,6 @@ CONFIG_PSTORE_BLK=m CONFIG_PSTORE_BLK_BLKDEV="" CONFIG_PSTORE_BLK_KMSG_SIZE=64 CONFIG_PSTORE_BLK_MAX_REASON=2 -# CONFIG_SYSV_FS is not set CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set # CONFIG_UFS_DEBUG is not set @@ -10852,6 +11122,7 @@ CONFIG_EROFS_FS_ZIP=y CONFIG_EROFS_FS_ZIP_LZMA=y CONFIG_EROFS_FS_ZIP_DEFLATE=y CONFIG_EROFS_FS_ZIP_ZSTD=y +CONFIG_EROFS_FS_ZIP_ACCEL=y CONFIG_EROFS_FS_ONDEMAND=y CONFIG_EROFS_FS_PCPU_KTHREAD=y CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI=y @@ -10888,6 +11159,7 @@ CONFIG_NFSD_SCSILAYOUT=y CONFIG_NFSD_V4_2_INTER_SSC=y CONFIG_NFSD_V4_SECURITY_LABEL=y # CONFIG_NFSD_LEGACY_CLIENT_TRACKING is not set +# CONFIG_NFSD_V4_DELEG_TIMESTAMPS is not set CONFIG_GRACE_PERIOD=m CONFIG_LOCKD=m CONFIG_LOCKD_V4=y @@ -10993,7 +11265,6 @@ CONFIG_NLS_UCS2_UTILS=m CONFIG_DLM=m CONFIG_DLM_DEBUG=y CONFIG_UNICODE=y -# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set CONFIG_IO_WQ=y # end of File systems @@ -11003,6 +11274,7 @@ CONFIG_IO_WQ=y CONFIG_KEYS=y CONFIG_KEYS_REQUEST_CACHE=y CONFIG_PERSISTENT_KEYRINGS=y +CONFIG_BIG_KEYS=y CONFIG_TRUSTED_KEYS=m CONFIG_HAVE_TRUSTED_KEYS=y CONFIG_TRUSTED_KEYS_TPM=y @@ -11016,6 +11288,7 @@ CONFIG_PROC_MEM_ALWAYS_FORCE=y # CONFIG_PROC_MEM_FORCE_PTRACE is not set # CONFIG_PROC_MEM_NO_FORCE is not set CONFIG_SECURITY=y +CONFIG_HAS_SECURITY_AUDIT=y CONFIG_SECURITYFS=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_INFINIBAND=y @@ -11023,8 +11296,6 @@ CONFIG_SECURITY_NETWORK_XFRM=y CONFIG_SECURITY_PATH=y # CONFIG_INTEL_TXT is not set CONFIG_LSM_MMAP_MIN_ADDR=65536 -CONFIG_HARDENED_USERCOPY=y -CONFIG_FORTIFY_SOURCE=y # CONFIG_STATIC_USERMODEHELPER is not set CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y @@ -11113,6 +11384,14 @@ CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y # CONFIG_ZERO_CALL_USED_REGS is not set # end of Memory initialization +# +# Bounds checking +# +CONFIG_FORTIFY_SOURCE=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_DEFAULT_ON=y +# end of Bounds checking + # # Hardening of kernel data structures # @@ -11124,7 +11403,7 @@ CONFIG_RANDSTRUCT_NONE=y # end of Kernel hardening options # end of Security options -CONFIG_XOR_BLOCKS=m +CONFIG_XOR_BLOCKS=y CONFIG_ASYNC_CORE=m CONFIG_ASYNC_MEMCPY=m CONFIG_ASYNC_XOR=m @@ -11153,17 +11432,16 @@ CONFIG_CRYPTO_AKCIPHER=y CONFIG_CRYPTO_KPP2=y CONFIG_CRYPTO_KPP=y CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_HKDF=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_MANAGER2=y CONFIG_CRYPTO_USER=m -CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_NULL2=m CONFIG_CRYPTO_PCRYPT=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_AUTHENC=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_KRB5ENC=m +# CONFIG_CRYPTO_BENCHMARK is not set CONFIG_CRYPTO_ENGINE=m # end of Crypto core or helper @@ -11206,16 +11484,15 @@ CONFIG_CRYPTO_TWOFISH_COMMON=m # CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_CHACHA20=m -CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_CTS=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_HCTR2=m -CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_XCTR=m -CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_NHPOLY1305=m # end of Length-preserving ciphers and modes @@ -11235,7 +11512,7 @@ CONFIG_CRYPTO_ESSIV=m # # Hashes, digests, and MACs # -CONFIG_CRYPTO_BLAKE2B=m +CONFIG_CRYPTO_BLAKE2B=y CONFIG_CRYPTO_CMAC=m CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_HMAC=y @@ -11243,28 +11520,23 @@ CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_POLYVAL=m -CONFIG_CRYPTO_POLY1305=m CONFIG_CRYPTO_RMD160=m CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_SHA3=y -CONFIG_CRYPTO_SM3=m CONFIG_CRYPTO_SM3_GENERIC=m CONFIG_CRYPTO_STREEBOG=m -CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_XXHASH=y # end of Hashes, digests, and MACs # # CRCs (cyclic redundancy checks) # -CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CRC32C=y CONFIG_CRYPTO_CRC32=m -CONFIG_CRYPTO_CRCT10DIF=y -CONFIG_CRYPTO_CRC64_ROCKSOFT=y # end of CRCs (cyclic redundancy checks) # @@ -11331,21 +11603,14 @@ CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64=m CONFIG_CRYPTO_ARIA_AESNI_AVX2_X86_64=m CONFIG_CRYPTO_ARIA_GFNI_AVX512_X86_64=m -CONFIG_CRYPTO_CHACHA20_X86_64=m CONFIG_CRYPTO_AEGIS128_AESNI_SSE2=m CONFIG_CRYPTO_NHPOLY1305_SSE2=m CONFIG_CRYPTO_NHPOLY1305_AVX2=m -CONFIG_CRYPTO_BLAKE2S_X86=y CONFIG_CRYPTO_POLYVAL_CLMUL_NI=m -CONFIG_CRYPTO_POLY1305_X86_64=m CONFIG_CRYPTO_SHA1_SSSE3=m -CONFIG_CRYPTO_SHA256_SSSE3=m CONFIG_CRYPTO_SHA512_SSSE3=m CONFIG_CRYPTO_SM3_AVX_X86_64=m CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m -CONFIG_CRYPTO_CRC32C_INTEL=m -CONFIG_CRYPTO_CRC32_PCLMUL=m -CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m # end of Accelerated Cryptographic Algorithms for CPU (x86) CONFIG_CRYPTO_HW=y @@ -11369,6 +11634,7 @@ CONFIG_CRYPTO_DEV_QAT_C3XXX=m CONFIG_CRYPTO_DEV_QAT_C62X=m CONFIG_CRYPTO_DEV_QAT_4XXX=m CONFIG_CRYPTO_DEV_QAT_420XX=m +CONFIG_CRYPTO_DEV_QAT_6XXX=m CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m CONFIG_CRYPTO_DEV_QAT_C3XXXVF=m CONFIG_CRYPTO_DEV_QAT_C62XVF=m @@ -11407,12 +11673,14 @@ CONFIG_SYSTEM_REVOCATION_KEYS="" CONFIG_SYSTEM_BLACKLIST_AUTH_UPDATE=y # end of Certificates for signature checking +CONFIG_CRYPTO_KRB5=m +# CONFIG_CRYPTO_KRB5_SELFTESTS is not set CONFIG_BINARY_PRINTF=y # # Library routines # -CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ=y # CONFIG_RAID6_PQ_BENCHMARK is not set CONFIG_LINEAR_RANGES=y CONFIG_PACKING=y @@ -11434,42 +11702,51 @@ CONFIG_ARCH_USE_SYM_ANNOTATIONS=y CONFIG_CRYPTO_LIB_UTILS=y CONFIG_CRYPTO_LIB_AES=y CONFIG_CRYPTO_LIB_AESCFB=y +CONFIG_CRYPTO_LIB_AESGCM=y CONFIG_CRYPTO_LIB_ARC4=m -CONFIG_CRYPTO_LIB_GF128MUL=m +CONFIG_CRYPTO_LIB_GF128MUL=y CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y -CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=m -CONFIG_CRYPTO_LIB_CHACHA_GENERIC=m -CONFIG_CRYPTO_LIB_CHACHA=m -CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519=m +CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=y +CONFIG_CRYPTO_LIB_CHACHA_GENERIC=y +CONFIG_CRYPTO_LIB_CHACHA=y +CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519=y CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=m +CONFIG_CRYPTO_LIB_CURVE25519_INTERNAL=m CONFIG_CRYPTO_LIB_CURVE25519=m CONFIG_CRYPTO_LIB_DES=m CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 -CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=m +CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=y CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m -CONFIG_CRYPTO_LIB_POLY1305=m -CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m +CONFIG_CRYPTO_LIB_POLY1305=y +CONFIG_CRYPTO_LIB_CHACHA20POLY1305=y CONFIG_CRYPTO_LIB_SHA1=y CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_ARCH_HAVE_LIB_SHA256=y +CONFIG_CRYPTO_ARCH_HAVE_LIB_SHA256_SIMD=y +CONFIG_CRYPTO_LIB_SHA256_GENERIC=y +CONFIG_CRYPTO_LIB_SM3=m +CONFIG_CRYPTO_BLAKE2S_X86=y +CONFIG_CRYPTO_CHACHA20_X86_64=y +CONFIG_CRYPTO_POLY1305_X86_64=y +CONFIG_CRYPTO_SHA256_X86_64=y # end of Crypto library routines CONFIG_CRC_CCITT=y -CONFIG_CRC16=m +CONFIG_CRC16=y CONFIG_CRC_T10DIF=y -CONFIG_CRC64_ROCKSOFT=y +CONFIG_ARCH_HAS_CRC_T10DIF=y +CONFIG_CRC_T10DIF_ARCH=y CONFIG_CRC_ITU_T=m CONFIG_CRC32=y -# CONFIG_CRC32_SELFTEST is not set -CONFIG_CRC32_SLICEBY8=y -# CONFIG_CRC32_SLICEBY4 is not set -# CONFIG_CRC32_SARWATE is not set -# CONFIG_CRC32_BIT is not set +CONFIG_ARCH_HAS_CRC32=y +CONFIG_CRC32_ARCH=y CONFIG_CRC64=y -CONFIG_CRC4=m +CONFIG_ARCH_HAS_CRC64=y +CONFIG_CRC64_ARCH=y CONFIG_CRC7=m -CONFIG_LIBCRC32C=m CONFIG_CRC8=m +CONFIG_CRC_OPTIMIZATIONS=y CONFIG_XXHASH=y # CONFIG_RANDOM32_SELFTEST is not set CONFIG_842_COMPRESS=m @@ -11559,6 +11836,7 @@ CONFIG_IRQ_POLL=y CONFIG_MPILIB=y CONFIG_SIGNATURE=y CONFIG_DIMLIB=y +CONFIG_LIBFDT=y CONFIG_OID_REGISTRY=y CONFIG_UCS2_STRING=y CONFIG_HAVE_GENERIC_VDSO=y @@ -11566,6 +11844,7 @@ CONFIG_GENERIC_GETTIMEOFDAY=y CONFIG_GENERIC_VDSO_TIME_NS=y CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT=y CONFIG_VDSO_GETRANDOM=y +CONFIG_GENERIC_VDSO_DATA_STORE=y CONFIG_FONT_SUPPORT=y CONFIG_FONTS=y CONFIG_FONT_8x8=y @@ -11600,6 +11879,8 @@ CONFIG_PLDMFW=y CONFIG_ASN1_ENCODER=m CONFIG_POLYNOMIAL=m CONFIG_FIRMWARE_TABLE=y +CONFIG_UNION_FIND=y +CONFIG_MIN_HEAP=y # # Kernel hacking @@ -11651,6 +11932,7 @@ CONFIG_STRIP_ASM_SYMS=y # CONFIG_DEBUG_SECTION_MISMATCH is not set CONFIG_SECTION_MISMATCH_WARN_ONLY=y CONFIG_OBJTOOL=y +# CONFIG_OBJTOOL_WERROR is not set # CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set # end of Compile-time checks and compiler options @@ -11680,6 +11962,7 @@ CONFIG_HAVE_KCSAN_COMPILER=y # CONFIG_NET_DEV_REFCNT_TRACKER is not set # CONFIG_NET_NS_REFCNT_TRACKER is not set # CONFIG_DEBUG_NET is not set +# CONFIG_DEBUG_NET_SMALL_RTNL is not set # end of Networking Debugging # @@ -11696,8 +11979,8 @@ CONFIG_PAGE_POISONING=y CONFIG_DEBUG_RODATA_TEST=y CONFIG_ARCH_HAS_DEBUG_WX=y CONFIG_DEBUG_WX=y -CONFIG_GENERIC_PTDUMP=y -CONFIG_PTDUMP_CORE=y +CONFIG_ARCH_HAS_PTDUMP=y +CONFIG_PTDUMP=y # CONFIG_PTDUMP_DEBUGFS is not set CONFIG_HAVE_DEBUG_KMEMLEAK=y # CONFIG_DEBUG_KMEMLEAK is not set @@ -11707,6 +11990,7 @@ CONFIG_SHRINKER_DEBUG=y # CONFIG_DEBUG_STACK_USAGE is not set CONFIG_SCHED_STACK_END_CHECK=y CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VFS is not set # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_VM_PGTABLE is not set CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y @@ -11753,6 +12037,7 @@ CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 # CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_DETECT_HUNG_TASK_BLOCKER=y # CONFIG_WQ_WATCHDOG is not set # CONFIG_WQ_CPU_INTENSIVE_REPORT is not set # CONFIG_TEST_LOCKUP is not set @@ -11761,12 +12046,10 @@ CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 # # Scheduler Debugging # -CONFIG_SCHED_DEBUG=y CONFIG_SCHED_INFO=y CONFIG_SCHEDSTATS=y # end of Scheduler Debugging -# CONFIG_DEBUG_TIMEKEEPING is not set # CONFIG_DEBUG_PREEMPT is not set # @@ -11830,11 +12113,13 @@ CONFIG_HAVE_RETHOOK=y CONFIG_RETHOOK=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_GRAPH_RETVAL=y +CONFIG_HAVE_FUNCTION_GRAPH_FREGS=y +CONFIG_HAVE_FTRACE_GRAPH_FUNC=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y +CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS=y CONFIG_HAVE_DYNAMIC_FTRACE_NO_PATCHABLE=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_SYSCALL_TRACEPOINTS=y @@ -11857,6 +12142,8 @@ CONFIG_BOOTTIME_TRACING=y CONFIG_FUNCTION_TRACER=y CONFIG_FUNCTION_GRAPH_TRACER=y CONFIG_FUNCTION_GRAPH_RETVAL=y +CONFIG_FUNCTION_GRAPH_RETADDR=y +CONFIG_FUNCTION_TRACE_ARGS=y CONFIG_DYNAMIC_FTRACE=y CONFIG_DYNAMIC_FTRACE_WITH_REGS=y CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y @@ -11950,7 +12237,6 @@ CONFIG_UNWINDER_ORC=y CONFIG_FUNCTION_ERROR_INJECTION=y # CONFIG_FAULT_INJECTION is not set CONFIG_ARCH_HAS_KCOV=y -CONFIG_CC_HAS_SANCOV_TRACE_PC=y # CONFIG_KCOV is not set CONFIG_RUNTIME_TESTING_MENU=y # CONFIG_TEST_DHRY is not set @@ -11968,8 +12254,6 @@ CONFIG_RUNTIME_TESTING_MENU=y CONFIG_ASYNC_RAID6_TEST=m # CONFIG_TEST_HEXDUMP is not set # CONFIG_TEST_KSTRTOX is not set -# CONFIG_TEST_PRINTF is not set -# CONFIG_TEST_SCANF is not set # CONFIG_TEST_BITMAP is not set # CONFIG_TEST_UUID is not set # CONFIG_TEST_XARRAY is not set @@ -11981,7 +12265,6 @@ CONFIG_ASYNC_RAID6_TEST=m # CONFIG_TEST_BITOPS is not set # CONFIG_TEST_VMALLOC is not set # CONFIG_TEST_BPF is not set -# CONFIG_TEST_BLACKHOLE_DEV is not set # CONFIG_FIND_BIT_BENCHMARK is not set # CONFIG_TEST_FIRMWARE is not set # CONFIG_TEST_SYSCTL is not set @@ -11989,6 +12272,7 @@ CONFIG_ASYNC_RAID6_TEST=m # CONFIG_TEST_STATIC_KEYS is not set # CONFIG_TEST_DYNAMIC_DEBUG is not set # CONFIG_TEST_KMOD is not set +# CONFIG_TEST_KALLSYMS is not set # CONFIG_TEST_MEMCAT_P is not set # CONFIG_TEST_OBJAGG is not set # CONFIG_TEST_MEMINIT is not set @@ -12005,5 +12289,10 @@ CONFIG_MEMTEST=y # # Rust hacking # +# CONFIG_RUST_DEBUG_ASSERTIONS is not set +CONFIG_RUST_OVERFLOW_CHECKS=y +# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set # end of Rust hacking # end of Kernel hacking + +CONFIG_IO_URING_ZCRX=y diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index eb2c8c3fd2..8457ab0584 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.15.config \ No newline at end of file +../../../configs/surface-6.16.config \ No newline at end of file From 08118d0f42e06a3fc47106c8d6d7669ab585d9bd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Sep 2025 18:53:31 +0200 Subject: [PATCH 125/236] Update Debian kernel to v6.16.9 --- ...secureboot-pre-signing-to-the-kernel.patch | 12 +++++----- ...-integrity-Only-use-machine-keyring-.patch | 4 ++-- ...sallow-unprivileged-CLONE_NEWUSER-by.patch | 24 +++++++++---------- ...uild-Copy-config-to-target-directory.patch | 4 ++-- ...001-kbuild-Link-sign-file-statically.patch | 4 ++-- pkg/debian/kernel/version.conf | 4 ++-- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch index bfcedb06b9..1feb343468 100644 --- a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch +++ b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch @@ -1,4 +1,4 @@ -From c9d3ed004787ac580252b06af2642e5bb5aaf265 Mon Sep 17 00:00:00 2001 +From 68aa2761f6a59f4e826c2a66b8d2cf4d26053ce0 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 22 Sep 2019 22:44:16 +0200 Subject: [PATCH] Add secureboot pre-signing to the kernel @@ -21,10 +21,10 @@ Signed-off-by: Dorian Stoll create mode 100755 scripts/sign_kernel.sh diff --git a/.gitignore b/.gitignore -index f2f63e47fb88..99638429fcbb 100644 +index 929054df5212..5a7019ba11d0 100644 --- a/.gitignore +++ b/.gitignore -@@ -159,6 +159,9 @@ signing_key.priv +@@ -161,6 +161,9 @@ signing_key.priv signing_key.x509 x509.genkey @@ -35,10 +35,10 @@ index f2f63e47fb88..99638429fcbb 100644 /all.config /alldef.config diff --git a/arch/x86/Makefile b/arch/x86/Makefile -index 594723005d95..a5c8c487e83d 100644 +index 1913d342969b..131d1110044c 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile -@@ -314,6 +314,7 @@ endif +@@ -320,6 +320,7 @@ endif $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE) $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@ @@ -83,5 +83,5 @@ index 000000000000..d2526a279254 +sbsign --key $BUILDDIR/keys/MOK.key --cert $BUILDDIR/keys/MOK.crt \ + --output $VMLINUX $VMLINUX -- -2.50.0 +2.51.0 diff --git a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch index b212d6922d..a7b02b31ff 100644 --- a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch +++ b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch @@ -1,4 +1,4 @@ -From 020939dbfdd44d08f1da5d9d980ce27176514009 Mon Sep 17 00:00:00 2001 +From 671aba7365d3ab2c900951b959c39ce6890e0080 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 22:54:05 +0100 Subject: [PATCH] Partially revert "integrity: Only use machine keyring when @@ -37,5 +37,5 @@ index a401640a63cd..a1ad244cbf86 100644 static bool __init trust_moklist(void) -- -2.50.0 +2.51.0 diff --git a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch index 232d05d790..fde2152559 100644 --- a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch +++ b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch @@ -1,4 +1,4 @@ -From f675a2222ecd97c5b85bf05901e3220ee90c30ba Mon Sep 17 00:00:00 2001 +From eaad52af3805d3bd81d56e5325054d0efc37f875 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Fri, 31 May 2013 19:12:12 +0100 Subject: [PATCH] add sysctl to disallow unprivileged CLONE_NEWUSER by default @@ -20,10 +20,10 @@ Signed-off-by: Serge Hallyn 3 files changed, 32 insertions(+) diff --git a/kernel/fork.c b/kernel/fork.c -index 168681fc4b25..74abab2c65c1 100644 +index 1ee8eb11f38b..59d8c7ba6c54 100644 --- a/kernel/fork.c +++ b/kernel/fork.c -@@ -119,6 +119,12 @@ +@@ -122,6 +122,12 @@ #include @@ -36,7 +36,7 @@ index 168681fc4b25..74abab2c65c1 100644 /* * Minimum number of threads to boot the kernel */ -@@ -2194,6 +2200,10 @@ __latent_entropy struct task_struct *copy_process( +@@ -1933,6 +1939,10 @@ __latent_entropy struct task_struct *copy_process( if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -47,7 +47,7 @@ index 168681fc4b25..74abab2c65c1 100644 /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. -@@ -3354,6 +3364,12 @@ int ksys_unshare(unsigned long unshare_flags) +@@ -3099,6 +3109,12 @@ int ksys_unshare(unsigned long unshare_flags) if (unshare_flags & CLONE_NEWNS) unshare_flags |= CLONE_FS; @@ -61,10 +61,10 @@ index 168681fc4b25..74abab2c65c1 100644 if (err) goto bad_unshare_out; diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 3b7a7308e35b..cb4bab6a39bf 100644 +index 9b4f0cff76ea..c388b1aa4d3d 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c -@@ -84,6 +84,10 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals); +@@ -77,6 +77,10 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals); static const int ngroups_max = NGROUPS_MAX; static const int cap_last_cap = CAP_LAST_CAP; @@ -75,10 +75,10 @@ index 3b7a7308e35b..cb4bab6a39bf 100644 #ifdef CONFIG_PROC_SYSCTL /** -@@ -1595,6 +1599,15 @@ static const struct ctl_table kern_table[] = { - .mode = 0644, - .proc_handler = proc_dointvec, - }, +@@ -1581,6 +1585,15 @@ int proc_do_static_key(const struct ctl_table *table, int write, + } + + static const struct ctl_table kern_table[] = { +#ifdef CONFIG_USER_NS + { + .procname = "unprivileged_userns_clone", @@ -106,5 +106,5 @@ index 682f40d5632d..bf265ad528f9 100644 static DEFINE_MUTEX(userns_state_mutex); -- -2.50.0 +2.51.0 diff --git a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch index 88019b6083..79e268aee1 100644 --- a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch +++ b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch @@ -1,4 +1,4 @@ -From b62686b48f37ac9a8807d3e26523226ff900c27c Mon Sep 17 00:00:00 2001 +From a85832b815c784d29d2287e22143bf3c0accf4b8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 03:02:20 +0200 Subject: [PATCH] kbuild: Copy config to target directory @@ -20,5 +20,5 @@ index b96538787f3d..718bd64d060e 100755 + find "${destdir}" \( -name '.*.cmd' -o -name '*.o' \) -delete -- -2.50.0 +2.51.0 diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index d9e06ed948..8875eac129 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -1,4 +1,4 @@ -From d31ef20443261b91cc47efbcc749369f5df29c95 Mon Sep 17 00:00:00 2001 +From 56d102e8604b6f22008583a51ccbc7477817231d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:10:28 +0200 Subject: [PATCH] kbuild: Link sign-file statically @@ -21,5 +21,5 @@ index 46f860529df5..7846e18ef5d8 100644 ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) -- -2.50.0 +2.51.0 diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index ccc1b45889..5f13c4dbdf 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.15.1" -KERNEL_REVISION="2" +KERNEL_VERSION="6.16.9" +KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 94217c2dc8818afd2296c3776223fc1c093f78fb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Sep 2025 20:24:23 +0200 Subject: [PATCH 126/236] Update Fedora kernels to v6.16.9 --- .../kernel-surface/build-linux-surface.py | 2 +- ...1-Pull-in-iptsd-as-a-weak-dependency.patch | 8 +-- ...ce-provide-the-standard-package-name.patch | 38 ++++++------ ...ce-conflict-with-older-versions-of-t.patch | 60 +++++++++---------- ...and-service-files-for-keeping-the-su.patch | 20 +++---- .../0005-Pull-in-intel-vsc-firmware.patch | 10 ++-- .../secureboot/0001-secureboot.patch | 12 ++-- 7 files changed, 75 insertions(+), 75 deletions(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 6bfb514426..b4a197df1b 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.15.3-0" +PACKAGE_TAG = "kernel-6.16.9-0" ## ## The release number of the modified kernel package. diff --git a/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch index 4c80306421..95a0b2c071 100644 --- a/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch +++ b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch @@ -1,4 +1,4 @@ -From a6efddbe9af597841afae20b6f046f96b5467609 Mon Sep 17 00:00:00 2001 +From 83a53f9f9e17797d5bb0a2eeb5208533d921b6d6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:33:03 +0200 Subject: [PATCH 1/5] Pull in iptsd as a weak dependency @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 7cc72d5a5c77..c11232e74d15 100644 +index bbe58bf955f0..9f48a4e6c91f 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1140,6 +1140,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1178,6 +1178,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index 7cc72d5a5c77..c11232e74d15 100644 Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -- -2.50.0 +2.51.0 diff --git a/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch index d885aecd5f..138f515edd 100644 --- a/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch +++ b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch @@ -1,6 +1,6 @@ -From 1d878cc13b3d4d5d50ad58b9a871ad2202a9c7ec Mon Sep 17 00:00:00 2001 +From b613bdf0b0520f8046cb837184b56946b5676002 Mon Sep 17 00:00:00 2001 From: Dorian Stoll -Date: Sat, 22 Jul 2023 10:34:38 +0200 +Date: Tue, 30 Sep 2025 20:09:20 +0200 Subject: [PATCH 2/5] Let kernel-surface provide the standard package names Signed-off-by: Dorian Stoll @@ -9,26 +9,26 @@ Signed-off-by: Dorian Stoll 1 file changed, 5 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index c11232e74d15..ca6517bdc945 100644 +index 9f48a4e6c91f..e6ef25cb0580 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -723,6 +723,7 @@ Requires: kernel-modules-uname-r = %{KVERREL} - Requires: kernel-modules-core-uname-r = %{KVERREL} - Requires: ((kernel-modules-extra-uname-r = %{KVERREL}) if kernel-modules-extra-matched) +@@ -734,6 +734,7 @@ Requires: %{name}-modules-uname-r = %{KVERREL} + Requires: %{name}-modules-core-uname-r = %{KVERREL} + Requires: ((%{name}-modules-extra-uname-r = %{KVERREL}) if %{name}-modules-extra-matched) Provides: installonlypkg(kernel) +Provides: kernel = %{KVERREL} %endif -@@ -1440,6 +1441,7 @@ Summary: Development package for building kernel modules to match the %{?2:%{2} - Provides: kernel%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release}\ - Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1:+%{1}}}\ - Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ -+Provides: kernel-devel = %{KVERREL}%{?1:+%{1}}\ +@@ -1484,6 +1485,7 @@ Provides: %{name}%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release} + Provides: %{name}-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ ++Provides: kernel-devel = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ AutoReqProv: no\ Requires(pre): findutils\ -@@ -1469,6 +1471,7 @@ against the %{?2:%{2} }kernel package.\ +@@ -1513,6 +1515,7 @@ against the %{?2:%{2} }kernel package.\ Summary: Meta package to install matching core and devel packages for a given %{?2:%{2} }kernel\ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ @@ -36,7 +36,7 @@ index c11232e74d15..ca6517bdc945 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1586,6 +1589,7 @@ Requires: ((kernel-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) +@@ -1630,6 +1633,7 @@ Requires: ((%{name}-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) Requires: realtime-setup\ %endif\ Provides: installonlypkg(kernel)\ @@ -44,14 +44,14 @@ index c11232e74d15..ca6517bdc945 100644 %description %{1}\ The meta-package for the %{1} kernel\ %{nil} -@@ -1600,6 +1604,7 @@ The meta-package for the %{1} kernel\ +@@ -1648,6 +1652,7 @@ The meta-package for the %{1} kernel\ Summary: %{variant_summary}\ - Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ + Provides: %{name}-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ -+Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{?1:+%{1}}\ ++Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{uname_suffix %{?1}}\ %if %{-m:1}%{!-m:0}\ - Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ - Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ + Requires: %{name}-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ + Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ -- -2.50.0 +2.51.0 diff --git a/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch index 85ed833c66..354dafd00f 100644 --- a/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch +++ b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch @@ -1,6 +1,6 @@ -From cb7cebc53abc4152d3db1e3e53b069792dd3171e Mon Sep 17 00:00:00 2001 +From 32f4f4868f746f57d765561035e9768da1f89138 Mon Sep 17 00:00:00 2001 From: Dorian Stoll -Date: Sat, 22 Jul 2023 10:40:32 +0200 +Date: Tue, 30 Sep 2025 20:10:38 +0200 Subject: [PATCH 3/5] Let kernel-surface conflict with older versions of the package @@ -10,11 +10,11 @@ Signed-off-by: Dorian Stoll 1 file changed, 18 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index ca6517bdc945..2be57434622c 100644 +index e6ef25cb0580..2211bde2aa5a 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -724,6 +724,10 @@ Requires: kernel-modules-core-uname-r = %{KVERREL} - Requires: ((kernel-modules-extra-uname-r = %{KVERREL}) if kernel-modules-extra-matched) +@@ -735,6 +735,10 @@ Requires: %{name}-modules-core-uname-r = %{KVERREL} + Requires: ((%{name}-modules-extra-uname-r = %{KVERREL}) if %{name}-modules-extra-matched) Provides: installonlypkg(kernel) Provides: kernel = %{KVERREL} + @@ -24,16 +24,16 @@ index ca6517bdc945..2be57434622c 100644 %endif -@@ -1443,6 +1447,8 @@ Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suff - Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ - Provides: kernel-devel = %{KVERREL}%{?1:+%{1}}\ +@@ -1487,6 +1491,8 @@ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: kernel-devel = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ +Conflicts: %{package_name}-devel < 6.3.7-2\ +Obsoletes: %{package_name}-devel < 6.3.7-2\ AutoReqProv: no\ Requires(pre): findutils\ Requires: findutils\ -@@ -1472,6 +1478,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ +@@ -1516,6 +1522,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ Provides: kernel-devel-matched = %{specrpmversion}-%{release}\ @@ -42,34 +42,34 @@ index ca6517bdc945..2be57434622c 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1520,6 +1528,8 @@ Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{? - Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ - Requires: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ - Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ +@@ -1564,6 +1572,8 @@ Provides: %{name}%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{ + Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +Conflicts: %{package_name}-modules-extra < 6.3.7-2\ +Obsoletes: %{package_name}-modules-extra < 6.3.7-2\ %if %{-m:1}%{!-m:0}\ - Requires: kernel-modules-extra-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ + Requires: %{name}-modules-extra-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1543,6 +1553,8 @@ Provides: installonlypkg(kernel-module)\ - Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ - Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ - Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ +@@ -1587,6 +1597,8 @@ Provides: installonlypkg(kernel-module)\ + Provides: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +Conflicts: %{package_name}-modules < 6.3.7-2\ +Obsoletes: %{package_name}-modules < 6.3.7-2\ %if %{-m:1}%{!-m:0}\ - Requires: kernel-modules-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ + Requires: %{name}-modules-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1565,6 +1577,8 @@ Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1: +@@ -1609,6 +1621,8 @@ Provides: %{name}-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1 Provides: installonlypkg(kernel-module)\ - Provides: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ - Requires: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ + Provides: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +Conflicts: %{package_name}-modules-core < 6.3.7-2\ +Obsoletes: %{package_name}-modules-core < 6.3.7-2\ %if %{-m:1}%{!-m:0}\ - Requires: kernel-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ + Requires: %{name}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1588,6 +1602,8 @@ Requires: ((kernel-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) +@@ -1632,6 +1646,8 @@ Requires: ((%{name}-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) %if "%{1}" == "rt" || "%{1}" == "rt-debug" || "%{1}" == "rt-64k" || "%{1}" == "rt-64k-debug"\ Requires: realtime-setup\ %endif\ @@ -78,15 +78,15 @@ index ca6517bdc945..2be57434622c 100644 Provides: installonlypkg(kernel)\ Provides: kernel = %{KVERREL}+%{1}\ %description %{1}\ -@@ -1605,6 +1621,8 @@ Summary: %{variant_summary}\ - Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ +@@ -1653,6 +1669,8 @@ Summary: %{variant_summary}\ + Provides: %{name}-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ - Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{?1:+%{1}}\ + Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{uname_suffix %{?1}}\ +Conflicts: %{package_name}-core < 6.3.7-2\ +Obsoletes: %{package_name}-core < 6.3.7-2\ %if %{-m:1}%{!-m:0}\ - Requires: kernel-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ - Requires: kernel-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1:+%{1}}}\ + Requires: %{name}-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ + Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ -- -2.50.0 +2.51.0 diff --git a/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch index af0d0dc319..f62a58e375 100644 --- a/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch +++ b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch @@ -1,6 +1,6 @@ -From 9254dd83c5727f0ee761af26bc36edd2f1921010 Mon Sep 17 00:00:00 2001 +From 76a02768150ead36dde30f77294cf4fd8bef06d2 Mon Sep 17 00:00:00 2001 From: Dorian Stoll -Date: Sat, 22 Jul 2023 10:41:11 +0200 +Date: Tue, 30 Sep 2025 20:12:29 +0200 Subject: [PATCH 4/5] Install scripts and service files for keeping the surface kernel the default @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 33 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 2be57434622c..e62247d054aa 100644 +index 2211bde2aa5a..561ae802e34f 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1113,6 +1113,11 @@ Source4000: README.rst +@@ -1148,6 +1148,11 @@ Source4000: README.rst Source4001: rpminspect.yaml Source4002: gating.yaml @@ -25,7 +25,7 @@ index 2be57434622c..e62247d054aa 100644 ## Patches needed for building this package %if !%{nopatches} -@@ -1146,6 +1151,7 @@ Requires(pre): %{initrd_prereq}\ +@@ -1184,6 +1189,7 @@ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ Recommends: iptsd\ @@ -33,7 +33,7 @@ index 2be57434622c..e62247d054aa 100644 Requires(preun): systemd >= 200\ Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -@@ -1160,6 +1166,13 @@ AutoProv: yes\ +@@ -1198,6 +1204,13 @@ AutoProv: yes\ %{nil} @@ -47,7 +47,7 @@ index 2be57434622c..e62247d054aa 100644 %package doc Summary: Various documentation bits found in the kernel source Group: Documentation -@@ -3366,6 +3379,11 @@ find Documentation -type d | xargs chmod u+w +@@ -3447,6 +3460,11 @@ find Documentation -type d | xargs chmod u+w cd linux-%{KVERREL} @@ -59,7 +59,7 @@ index 2be57434622c..e62247d054aa 100644 # re-define RPM_VMLINUX_H, because it doesn't carry over from %build RPM_VMLINUX_H="$(cat ../vmlinux_h_path)" -@@ -3651,6 +3669,15 @@ popd +@@ -3750,6 +3768,15 @@ popd ### scripts ### @@ -75,7 +75,7 @@ index 2be57434622c..e62247d054aa 100644 %if %{with_tools} %post -n %{package_name}-tools-libs /sbin/ldconfig -@@ -4118,6 +4145,12 @@ fi\ +@@ -4222,6 +4249,12 @@ fi\ %{_libexecdir}/kselftests %endif @@ -89,5 +89,5 @@ index 2be57434622c..e62247d054aa 100644 %if %{with_up_base} %ifnarch %nobuildarches noarch -- -2.50.0 +2.51.0 diff --git a/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch index b8e2bcc8a1..12340dd664 100644 --- a/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch +++ b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch @@ -1,6 +1,6 @@ -From 53705991e1729c45d4f67442f4f960fac6cbe6fe Mon Sep 17 00:00:00 2001 +From f6344afdfee91f53c535288b0e47818779360129 Mon Sep 17 00:00:00 2001 From: Dorian Stoll -Date: Mon, 29 Jan 2024 19:26:41 +0100 +Date: Tue, 30 Sep 2025 20:14:00 +0200 Subject: [PATCH 5/5] Pull in intel-vsc-firmware This package contains the IPU3 firmware needed for camera support. @@ -9,10 +9,10 @@ This package contains the IPU3 firmware needed for camera support. 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index e62247d054aa..2a649e791854 100644 +index 561ae802e34f..e2c9ffe3c52e 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1150,6 +1150,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1188,6 +1188,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index e62247d054aa..2a649e791854 100644 Recommends: %{package_name}-default-watchdog\ Requires(preun): systemd >= 200\ -- -2.50.0 +2.51.0 diff --git a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch index 8dcd54c6bb..2b2cb43403 100644 --- a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch +++ b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 3a1ef54d409e25bd0d5f52e1c0f7f226668e79c3 Mon Sep 17 00:00:00 2001 +From e59f7b88079429cd5c373e4518864a87135d2bf8 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:45:33 +0200 Subject: [PATCH] Use a custom key and certificate for Secure Boot signing @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index c0201430e851..7a70246dc91b 100644 +index ca141beda4fd..bbe58bf955f0 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -774,6 +774,7 @@ BuildRequires: system-sb-certs +@@ -849,6 +849,7 @@ BuildRequires: system-sb-certs %ifarch x86_64 aarch64 riscv64 BuildRequires: nss-tools BuildRequires: pesign >= 0.10-4 @@ -20,7 +20,7 @@ index c0201430e851..7a70246dc91b 100644 %endif %endif %endif -@@ -847,6 +848,13 @@ Source13: redhatsecureboot501.cer +@@ -942,6 +943,13 @@ Source13: redhatsecureboot501.cer %define signing_key_filename kernel-signing-s390.cer %endif @@ -34,7 +34,7 @@ index c0201430e851..7a70246dc91b 100644 # Fedora/ELN pesign macro expects to see these cert file names, see: # https://github.com/rhboot/pesign/blob/main/src/pesign-rpmbuild-helper.in#L216 %if 0%{?fedora}%{?eln} -@@ -2235,7 +2243,7 @@ BuildKernel() { +@@ -2373,7 +2381,7 @@ BuildKernel() { %ifarch x86_64 aarch64 %{log_msg "Sign kernel image"} @@ -44,5 +44,5 @@ index c0201430e851..7a70246dc91b 100644 %ifarch s390x ppc64le if [ -x /usr/bin/rpm-sign ]; then -- -2.47.0 +2.51.0 From d2ede7885837de078fe995eb05d8fb1b64b11651 Mon Sep 17 00:00:00 2001 From: Apiznel Date: Sun, 5 Oct 2025 15:20:38 -0400 Subject: [PATCH 127/236] Update v6.16 patches Changes: - Rebase onto v6.16.10 --- patches/6.16/0001-secureboot.patch | 4 +- patches/6.16/0002-surface3.patch | 4 +- patches/6.16/0003-mwifiex.patch | 6 +- patches/6.16/0004-ath10k.patch | 2 +- patches/6.16/0005-ipts.patch | 6 +- patches/6.16/0006-ithc.patch | 4 +- patches/6.16/0007-surface-sam.patch | 4 +- patches/6.16/0008-surface-sam-over-hid.patch | 4 +- patches/6.16/0009-surface-button.patch | 4 +- patches/6.16/0010-surface-typecover.patch | 70 ++++++++++---------- patches/6.16/0011-surface-shutdown.patch | 2 +- patches/6.16/0012-surface-gpe.patch | 2 +- patches/6.16/0013-cameras.patch | 18 ++--- patches/6.16/0014-amd-gpio.patch | 4 +- patches/6.16/0015-rtc.patch | 2 +- 15 files changed, 68 insertions(+), 68 deletions(-) diff --git a/patches/6.16/0001-secureboot.patch b/patches/6.16/0001-secureboot.patch index 66c06f1908..567ed4ad84 100644 --- a/patches/6.16/0001-secureboot.patch +++ b/patches/6.16/0001-secureboot.patch @@ -1,4 +1,4 @@ -From e87eeb0fa251c56d9966ad1e59b261ee0b14a566 Mon Sep 17 00:00:00 2001 +From ef381b568568d83624a9f527b394528bbf9f9cc4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index e1f4fd5bc8ee..64f8dc548045 100644 -- 2.51.0 -From d697f8d42f404ba2615c63a36f3ce73931dcf2ea Mon Sep 17 00:00:00 2001 +From 2a3d0ca06b2a6f7c9f206b06886095f1d7658c94 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.16/0002-surface3.patch b/patches/6.16/0002-surface3.patch index 082cf31f61..02c19042eb 100644 --- a/patches/6.16/0002-surface3.patch +++ b/patches/6.16/0002-surface3.patch @@ -1,4 +1,4 @@ -From 594f39a9ca0f976ec3ab30fa6852ad4c2b4831a0 Mon Sep 17 00:00:00 2001 +From 0d1d229f54a68e14ee69bececce8fd06dbb1287e Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.51.0 -From 48541ded57baafc01b4a738a056c3ccec25c8df1 Mon Sep 17 00:00:00 2001 +From a5550b1de4700806a951fa58da2c7db0cb3a51c6 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.16/0003-mwifiex.patch b/patches/6.16/0003-mwifiex.patch index 99b935a418..e275bcade5 100644 --- a/patches/6.16/0003-mwifiex.patch +++ b/patches/6.16/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From ac77045658a4d9764b9a6395e7b193ed14414ff5 Mon Sep 17 00:00:00 2001 +From 5ebd733c7a2faf6442fdbb64620664c6c74a3c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.51.0 -From f57cfe5a93d9d0bd3024367ffa9c99812feab8e0 Mon Sep 17 00:00:00 2001 +From 7fc537753e00ffba79cd3b93cff948569d0f85a0 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.51.0 -From 4c7809f1af22d2502869a90f8958f89ef7bc0a0c Mon Sep 17 00:00:00 2001 +From b13ce3956e2c84e8e0f9ede608419981c47238ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.16/0004-ath10k.patch b/patches/6.16/0004-ath10k.patch index 8e83e1928f..92f146b30e 100644 --- a/patches/6.16/0004-ath10k.patch +++ b/patches/6.16/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 61461ed065cb724b5fc971cb0c5272ef3313a42f Mon Sep 17 00:00:00 2001 +From 509e9d1b4d4803b7b3061cae155b92b5129b8569 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.16/0005-ipts.patch b/patches/6.16/0005-ipts.patch index 0e12d537e0..0c456b5902 100644 --- a/patches/6.16/0005-ipts.patch +++ b/patches/6.16/0005-ipts.patch @@ -1,4 +1,4 @@ -From 0ada79877cefaf982ffd379465e225042a283208 Mon Sep 17 00:00:00 2001 +From 766b671b7b337d44a2d543e038af19705b65dc32 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 3f9c60b579ae..853a67753333 100644 -- 2.51.0 -From 3153c571ead4689a56c8b6cf35a3030e6cff7683 Mon Sep 17 00:00:00 2001 +From 52ab7cdaafa370cdaca812debc559a4c4f28afc5 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index 3dd4d73fcb5d..98def863f736 100644 -- 2.51.0 -From 7929eb6116ecdfacbf0bd288ae8f57a03f00b81a Mon Sep 17 00:00:00 2001 +From a94045db4fab0ee662697cdc70473e7162702b0a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.16/0006-ithc.patch b/patches/6.16/0006-ithc.patch index 2a49c75fe0..4104f00d06 100644 --- a/patches/6.16/0006-ithc.patch +++ b/patches/6.16/0006-ithc.patch @@ -1,4 +1,4 @@ -From 020ac25e7bf02edab684906a300a8624e2353b0d Mon Sep 17 00:00:00 2001 +From 1e8740a68d6ca59e6814a7470d04f139240c0c30 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index cf7b6882ec75..55ab16865774 100644 -- 2.51.0 -From f698eb55ef20a37e5724d7e8f5cb609d12fcabcc Mon Sep 17 00:00:00 2001 +From 6253e4bc033038c1e682057b7992692b517c7231 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.16/0007-surface-sam.patch b/patches/6.16/0007-surface-sam.patch index e4534b697e..89ec00cf00 100644 --- a/patches/6.16/0007-surface-sam.patch +++ b/patches/6.16/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From b83775761995a645f0c958d518ae0e9dc2c40cb7 Mon Sep 17 00:00:00 2001 +From 1578f4db9e0da5dc08d1169cc6694474b9ab9ab7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.51.0 -From d8f161cde861f572e191a8f7baa59d8e55051799 Mon Sep 17 00:00:00 2001 +From 6871f7ece4ce979923ea83e19c3cd2830188b4c5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.16/0008-surface-sam-over-hid.patch b/patches/6.16/0008-surface-sam-over-hid.patch index 5df78a93da..1c7b32f574 100644 --- a/patches/6.16/0008-surface-sam-over-hid.patch +++ b/patches/6.16/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From e65ba8e7b543f1a0af66062d05d9d98c4602a8ad Mon Sep 17 00:00:00 2001 +From f5015fb9b2720652748f6bbc7ed8eb0adea07854 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index f43067f6797e..1761ca30e17a 100644 -- 2.51.0 -From c9c5d92d081d485de80aad30f535768848263247 Mon Sep 17 00:00:00 2001 +From 4972b5ba149ead25f9b3300674225788043b40d2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.16/0009-surface-button.patch b/patches/6.16/0009-surface-button.patch index 3dbb165f9a..c34b1644f9 100644 --- a/patches/6.16/0009-surface-button.patch +++ b/patches/6.16/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 13a6e5683a378d75df86470a039bb41d9d98e7eb Mon Sep 17 00:00:00 2001 +From 55168a263afd9a033c00ff9625b6324345d9405c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.51.0 -From de2da3530b7fda779b5b5eb86b1f2d35087828fd Mon Sep 17 00:00:00 2001 +From bb174e7f9377b9f0afce68e2e52ceaf3584950a5 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.16/0010-surface-typecover.patch b/patches/6.16/0010-surface-typecover.patch index 0d292fa0d0..89d4958220 100644 --- a/patches/6.16/0010-surface-typecover.patch +++ b/patches/6.16/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 0c9d7910c676745bcbac6439f0fd0697ec0dd327 Mon Sep 17 00:00:00 2001 +From 84deac886f50cf811673ad70953d5ab79b89617f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index d6daad39491b..2e50dd89b800 100644 +index f5bc53875330..31fa895d73c4 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -39,7 +39,7 @@ index d6daad39491b..2e50dd89b800 100644 -- 2.51.0 -From 096340b6ad9ccc772d7f1be6ea455f48ee5f72a4 Mon Sep 17 00:00:00 2001 +From 8c85bf8003cf8dcbe8f04a100474513a10e3f207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 4c22bd2ba170..e231393da178 100644 +index edb8da49d916..650df45e9f13 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -97,11 +97,11 @@ index 4c22bd2ba170..e231393da178 100644 /* quirks to control the device */ #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) -@@ -73,12 +77,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) +@@ -74,12 +78,15 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_DISABLE_WAKEUP BIT(21) #define MT_QUIRK_ORIENTATION_INVERT BIT(22) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -113,7 +113,7 @@ index 4c22bd2ba170..e231393da178 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -176,6 +183,8 @@ struct mt_device { +@@ -177,6 +184,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -122,7 +122,7 @@ index 4c22bd2ba170..e231393da178 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -220,6 +229,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); +@@ -221,6 +230,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_GOOGLE 0x0111 #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 #define MT_CLS_SMART_TECH 0x0113 @@ -130,7 +130,7 @@ index 4c22bd2ba170..e231393da178 100644 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -410,6 +420,16 @@ static const struct mt_class mt_classes[] = { +@@ -411,6 +421,16 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, }, @@ -147,7 +147,7 @@ index 4c22bd2ba170..e231393da178 100644 { } }; -@@ -1767,6 +1787,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1802,6 +1822,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index 4c22bd2ba170..e231393da178 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1790,6 +1873,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1825,6 +1908,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index 4c22bd2ba170..e231393da178 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1828,8 +1914,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1863,8 +1949,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index 4c22bd2ba170..e231393da178 100644 if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1838,8 +1926,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1873,8 +1961,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index 4c22bd2ba170..e231393da178 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1889,6 +1979,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1924,6 +2014,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index 4c22bd2ba170..e231393da178 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2328,6 +2419,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2363,6 +2454,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -274,7 +274,7 @@ index 4c22bd2ba170..e231393da178 100644 -- 2.51.0 -From dd133146d7777b2793f31952b45dbcc9fd89e900 Mon Sep 17 00:00:00 2001 +From b4e3dfa79f33a0e59e7054ae764f2026f93a0113 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,18 +303,18 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e231393da178..d9b80e1dd3c6 100644 +index 650df45e9f13..bb63fe858d87 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) +@@ -79,6 +79,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_ORIENTATION_INVERT BIT(22) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -85,6 +86,8 @@ MODULE_LICENSE("GPL"); +@@ -86,6 +87,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_CLICKPAD 0 #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 @@ -323,7 +323,7 @@ index e231393da178..d9b80e1dd3c6 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -422,6 +425,7 @@ static const struct mt_class mt_classes[] = { +@@ -423,6 +426,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -331,7 +331,7 @@ index e231393da178..d9b80e1dd3c6 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1403,6 +1407,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1438,6 +1442,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -341,7 +341,7 @@ index e231393da178..d9b80e1dd3c6 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1430,6 +1437,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1465,6 +1472,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -363,7 +363,7 @@ index e231393da178..d9b80e1dd3c6 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1451,6 +1473,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1486,6 +1508,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -371,7 +371,7 @@ index e231393da178..d9b80e1dd3c6 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1458,6 +1481,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1493,6 +1516,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -391,7 +391,7 @@ index e231393da178..d9b80e1dd3c6 100644 /* let hid-core decide for the others */ return 0; } -@@ -1467,11 +1503,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1502,11 +1538,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -413,7 +413,7 @@ index e231393da178..d9b80e1dd3c6 100644 return 0; } -@@ -1654,6 +1700,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1689,6 +1735,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index e231393da178..d9b80e1dd3c6 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1702,6 +1784,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1737,6 +1819,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index e231393da178..d9b80e1dd3c6 100644 default: suffix = "UNKNOWN"; break; -@@ -1787,30 +1876,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1822,30 +1911,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index e231393da178..d9b80e1dd3c6 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1819,8 +1884,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1854,8 +1919,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index e231393da178..d9b80e1dd3c6 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -1957,13 +2023,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -1992,13 +2058,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index e231393da178..d9b80e1dd3c6 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1972,12 +2049,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -2007,12 +2084,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); diff --git a/patches/6.16/0011-surface-shutdown.patch b/patches/6.16/0011-surface-shutdown.patch index 39853cfbc6..6bb1bf21eb 100644 --- a/patches/6.16/0011-surface-shutdown.patch +++ b/patches/6.16/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 9653abf64529b1ac674213c039d3d1be04dd853d Mon Sep 17 00:00:00 2001 +From 29accd39e3da7cc94b35a062853509f1de3d9e1d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.16/0012-surface-gpe.patch b/patches/6.16/0012-surface-gpe.patch index 155224fa40..178ba7dcac 100644 --- a/patches/6.16/0012-surface-gpe.patch +++ b/patches/6.16/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 81c20c9fb321319c93fa3d89de5842c9916309df Mon Sep 17 00:00:00 2001 +From f0ec37bb5b3ce1f5d651c6c422b3a1451b73d158 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.16/0013-cameras.patch b/patches/6.16/0013-cameras.patch index 512f731b98..6c997b9bdb 100644 --- a/patches/6.16/0013-cameras.patch +++ b/patches/6.16/0013-cameras.patch @@ -1,4 +1,4 @@ -From 6d3b7898c2d4ca1e93bca6467377087e59b4fe6e Mon Sep 17 00:00:00 2001 +From cfe2852b5ec7fb20b7f0308a075680cbfeaf7705 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index fb1fe9f3b1a3..5be8893b3912 100644 -- 2.51.0 -From 963e4c165afc61c5faba46f8ca20c1d0b2932db7 Mon Sep 17 00:00:00 2001 +From cf577fc4e338d0c1d1fcae2fe865f2d918576da9 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 98def863f736..15af4773df7e 100644 -- 2.51.0 -From a61ad0677bd36ec052487ab4cef6101d8138d6f1 Mon Sep 17 00:00:00 2001 +From 0c5ca0dd30fa269db29ec608313418e87de3740a Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.51.0 -From 39e4ca443f7436678999b2e4c63fe6c7c79b821a Mon Sep 17 00:00:00 2001 +From 2f2889ce527f770d01a15fbbe60af475898d673b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 3226888d77e9..3bfe45b764f7 100644 -- 2.51.0 -From 67898bb4c736f5846c66fd7737154cdc0ba5e1cd Mon Sep 17 00:00:00 2001 +From 13b8a5bf77dba2eb32fba569c1c619d6a484dbbb Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.51.0 -From be89734907a8d9bc31e1ecb96680d7d1bb94150d Mon Sep 17 00:00:00 2001 +From 6a9f73420a018f4ee807b06a7aedaa5a3abdeecd Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.51.0 -From acf6a36fee44848bea5ef5ab5394a42f37c5b9bf Mon Sep 17 00:00:00 2001 +From 0b974c7f54cf8e827bda14dc9b4e8830ab7e7b21 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.51.0 -From 51508796651e42174d2a1105159d66fa4e3ad809 Mon Sep 17 00:00:00 2001 +From 2b99d15b534e9c291557225dfc87b710cf97e026 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.51.0 -From dae5c7687ff0f6becfb72b4144e54f7022e54c11 Mon Sep 17 00:00:00 2001 +From 7890a9f304c08fd53a218520e9f89a64c1c65c15 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.16/0014-amd-gpio.patch b/patches/6.16/0014-amd-gpio.patch index 7ed30e117c..620d58151d 100644 --- a/patches/6.16/0014-amd-gpio.patch +++ b/patches/6.16/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 05505e5575eb38c3dff121869c72c8c224063f9c Mon Sep 17 00:00:00 2001 +From 48d639e6d267d1c87265b284bb2a511d46d8b776 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95eb3..8914a922be2b 100644 -- 2.51.0 -From 6df4d2ebe1e08d1907af8c90bb152843c465b3d9 Mon Sep 17 00:00:00 2001 +From 15fee80b2eed64de9f8a4bba533520476d7c9276 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.16/0015-rtc.patch b/patches/6.16/0015-rtc.patch index e9d9916b69..3fe174553c 100644 --- a/patches/6.16/0015-rtc.patch +++ b/patches/6.16/0015-rtc.patch @@ -1,4 +1,4 @@ -From bc0020cb77950499ba8166abe4e0b08ebd1aeb21 Mon Sep 17 00:00:00 2001 +From 160e5f8ff4b9b34fea0cf2575939470cd5d8a63b Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From 91786c371cc7d1c49ca17679243efd614b22e7ec Mon Sep 17 00:00:00 2001 From: Apiznel Date: Sun, 5 Oct 2025 22:16:52 -0400 Subject: [PATCH 128/236] Fix typo in surface shutdown patch --- patches/6.10/0011-surface-shutdown.patch | 2 +- patches/6.11/0011-surface-shutdown.patch | 2 +- patches/6.12/0010-surface-shutdown.patch | 2 +- patches/6.13/0011-surface-shutdown.patch | 2 +- patches/6.14/0011-surface-shutdown.patch | 2 +- patches/6.15/0011-surface-shutdown.patch | 2 +- patches/6.16/0011-surface-shutdown.patch | 2 +- patches/6.17/0011-surface-shutdown.patch | 2 +- patches/6.6/0010-surface-shutdown.patch | 2 +- patches/6.9/0011-surface-shutdown.patch | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/patches/6.10/0011-surface-shutdown.patch b/patches/6.10/0011-surface-shutdown.patch index 28a8ca6cad..6b4bfe3bf5 100644 --- a/patches/6.10/0011-surface-shutdown.patch +++ b/patches/6.10/0011-surface-shutdown.patch @@ -1,7 +1,7 @@ From fe6c6b6e8d581aeca114902ec5f962a44a0ee3ff Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.11/0011-surface-shutdown.patch b/patches/6.11/0011-surface-shutdown.patch index cba0afc4a9..573f651d42 100644 --- a/patches/6.11/0011-surface-shutdown.patch +++ b/patches/6.11/0011-surface-shutdown.patch @@ -1,7 +1,7 @@ From 44765b95447983e3e02aa26937c6b04266f09461 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index 9194e85fe8..704bdbc663 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,7 +1,7 @@ From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.13/0011-surface-shutdown.patch b/patches/6.13/0011-surface-shutdown.patch index 47d83dd0a8..5fec755a53 100644 --- a/patches/6.13/0011-surface-shutdown.patch +++ b/patches/6.13/0011-surface-shutdown.patch @@ -1,7 +1,7 @@ From a8fd28a346634ae41963cabaa22c249c66289cf6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.14/0011-surface-shutdown.patch b/patches/6.14/0011-surface-shutdown.patch index 4fe55ac91c..149ba60de5 100644 --- a/patches/6.14/0011-surface-shutdown.patch +++ b/patches/6.14/0011-surface-shutdown.patch @@ -1,7 +1,7 @@ From b19ebe86f0efac469f91581fe6ee53bce4586bc2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.15/0011-surface-shutdown.patch b/patches/6.15/0011-surface-shutdown.patch index 772c36439e..2445440980 100644 --- a/patches/6.15/0011-surface-shutdown.patch +++ b/patches/6.15/0011-surface-shutdown.patch @@ -1,7 +1,7 @@ From 46248cbac7ca6e688ebe5be29344239c78a884a7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.16/0011-surface-shutdown.patch b/patches/6.16/0011-surface-shutdown.patch index 6bb1bf21eb..0fef5cd5c4 100644 --- a/patches/6.16/0011-surface-shutdown.patch +++ b/patches/6.16/0011-surface-shutdown.patch @@ -1,7 +1,7 @@ From 29accd39e3da7cc94b35a062853509f1de3d9e1d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.17/0011-surface-shutdown.patch b/patches/6.17/0011-surface-shutdown.patch index 443b50bdd7..bb2c37c240 100644 --- a/patches/6.17/0011-surface-shutdown.patch +++ b/patches/6.17/0011-surface-shutdown.patch @@ -1,7 +1,7 @@ From 269ce75e30d184b81b8b40bb0c1bee28abe95082 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.6/0010-surface-shutdown.patch b/patches/6.6/0010-surface-shutdown.patch index 7c0e9b2ba7..1d403c0550 100644 --- a/patches/6.6/0010-surface-shutdown.patch +++ b/patches/6.6/0010-surface-shutdown.patch @@ -1,7 +1,7 @@ From b57c1784927f0ef467efdee4cb2a026d7eea3c1c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with diff --git a/patches/6.9/0011-surface-shutdown.patch b/patches/6.9/0011-surface-shutdown.patch index 17954bdc41..5a4d4eade5 100644 --- a/patches/6.9/0011-surface-shutdown.patch +++ b/patches/6.9/0011-surface-shutdown.patch @@ -1,7 +1,7 @@ From 6ab472fbfe2677b038998f6482da35a7daf3c14d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with From 1e59f0e6a1f152ca35e55ed4ec5b9e0757419953 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Fri, 10 Oct 2025 20:50:14 -0400 Subject: [PATCH 129/236] Add camera support for Surface Pro 9 - Add support for OV5693 and OV13858 camera sensors - Patch Intel INT3472 driver for camera power management - Update IPU bridge for Surface Pro 9 compatibility --- .../surface-pro9-camera-support.patch | 333 ++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 patches/experimental/surface-pro9-camera-support.patch diff --git a/patches/experimental/surface-pro9-camera-support.patch b/patches/experimental/surface-pro9-camera-support.patch new file mode 100644 index 0000000000..aaef9e9d00 --- /dev/null +++ b/patches/experimental/surface-pro9-camera-support.patch @@ -0,0 +1,333 @@ +--- a/drivers/media/i2c/ov5693.c ++++ b/drivers/media/i2c/ov5693.c +@@ -1403,6 +1403,7 @@ + + static const struct acpi_device_id ov5693_acpi_match[] = { + {"INT33BE"}, ++ {"OVTI5693"}, + {}, + }; + MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); + +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -58,6 +58,10 @@ + IPU_SENSOR_CONFIG("INT0310", 0), + /* Omnivision OV5693 */ + IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), ++ /* Omnivision OV5693 - Surface Pro 9 */ ++ IPU_SENSOR_CONFIG("OVTI5693", 1, 419200000), ++ /* Omnivision OV13858 - Surface Pro 9 */ ++ IPU_SENSOR_CONFIG("OVTID858", 4, 540000000), + /* Omnivision OV2740 */ + IPU_SENSOR_CONFIG("INT3474", 1, 180000000), + /* Omnivision OV5670 */ + +--- a/drivers/media/i2c/ov13858.c ++++ b/drivers/media/i2c/ov13858.c +@@ -2,6 +2,8 @@ + // Copyright (c) 2017 Intel Corporation. + + #include ++#include ++#include + #include + #include + #include +@@ -118,6 +120,14 @@ + struct ov13858_reg_list reg_list; + }; + ++// Or use standard names that might be more correct: ++static const char * const ov13858_supply_names[] = { ++ "avdd", // Analog voltage ++ "pwr1", // Digital core voltage ++}; ++ ++#define OV13858_NUM_SUPPLIES ARRAY_SIZE(ov13858_supply_names) ++ + /* 4224x3136 needs 1080Mbps/lane, 4 lanes */ + static const struct ov13858_reg mipi_data_rate_1080mbps[] = { + /* PLL1 registers */ +@@ -1041,13 +1051,131 @@ + + /* Current mode */ + const struct ov13858_mode *cur_mode; +- ++ struct regulator_bulk_data supplies[OV13858_NUM_SUPPLIES]; ++ struct gpio_desc *reset; ++ struct clk *xvclk; + /* Mutex for serialized access */ + struct mutex mutex; + }; + + #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) + ++ ++static int ov13858_get_regulators(struct ov13858 *ov13858) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); ++ unsigned int i; ++ ++ for (i = 0; i < OV13858_NUM_SUPPLIES; i++) ++ ov13858->supplies[i].supply = ov13858_supply_names[i]; ++ ++ return devm_regulator_bulk_get(&client->dev, OV13858_NUM_SUPPLIES, ++ ov13858->supplies); ++} ++ ++static int ov13858_sensor_powerup(struct ov13858 *ov13858) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); ++ int ret; ++ ++ dev_info(&client->dev, "Powering up sensor\n"); ++ ++ /* Assert reset */ ++ gpiod_set_value_cansleep(ov13858->reset, 1); ++ ++ /* Enable clock FIRST - sensor needs clock to communicate */ ++ ret = clk_prepare_enable(ov13858->xvclk); ++ if (ret) { ++ dev_err(&client->dev, "Failed to enable clock: %d\n", ret); ++ return ret; ++ } ++ dev_info(&client->dev, "Clock enabled\n"); ++ ++ /* Enable regulators */ ++ ret = regulator_bulk_enable(OV13858_NUM_SUPPLIES, ov13858->supplies); ++ if (ret) { ++ dev_err(&client->dev, "Failed to enable regulators: %d\n", ret); ++ clk_disable_unprepare(ov13858->xvclk); ++ return ret; ++ } ++ ++ dev_info(&client->dev, "Regulators enabled\n"); ++ ++ /* Wait for power to stabilize */ ++ usleep_range(5000, 10000); ++ ++ /* De-assert reset */ ++ gpiod_set_value_cansleep(ov13858->reset, 0); ++ ++ /* Wait for sensor to boot */ ++ msleep(20); ++ ++ dev_info(&client->dev, "Reset de-asserted, sensor should be ready\n"); ++ ++ return 0; ++} ++ ++static void ov13858_sensor_powerdown(struct ov13858 *ov13858) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); ++ ++ dev_info(&client->dev, "Powering down sensor\n"); ++ ++ /* Assert reset to put sensor in reset state */ ++ gpiod_set_value_cansleep(ov13858->reset, 1); ++ ++ /* Disable regulators */ ++ regulator_bulk_disable(OV13858_NUM_SUPPLIES, ov13858->supplies); ++ dev_info(&client->dev, "Regulators disabled\n"); ++ ++ /* Disable clock */ ++ clk_disable_unprepare(ov13858->xvclk); ++ dev_info(&client->dev, "Clock disabled\n"); ++} ++ ++static int __maybe_unused ov13858_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov13858 *ov13858 = to_ov13858(sd); ++ ++ ov13858_sensor_powerdown(ov13858); ++ ++ return 0; ++} ++ ++static int __maybe_unused ov13858_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov13858 *ov13858 = to_ov13858(sd); ++ int ret; ++ ++ ret = ov13858_sensor_powerup(ov13858); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ov13858_pm_ops = { ++ SET_RUNTIME_PM_OPS(ov13858_suspend, ov13858_resume, NULL) ++}; ++ ++static int ov13858_get_gpios(struct ov13858 *ov13858) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); ++ ++ ov13858->reset = devm_gpiod_get_optional(&client->dev, "reset", ++ GPIOD_OUT_HIGH); ++ if (IS_ERR(ov13858->reset)) { ++ dev_err(&client->dev, "Error fetching reset GPIO\n"); ++ return PTR_ERR(ov13858->reset); ++ } ++ ++ return 0; ++} ++ + /* Read registers up to 4 at a time */ + static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, + u32 *val) +@@ -1499,8 +1627,11 @@ + int ret; + u32 val; + ++ dev_info(&client->dev, "Attempting to read chip ID from register 0x300a\n"); + ret = ov13858_read_reg(ov13858, OV13858_REG_CHIP_ID, + OV13858_REG_VALUE_24BIT, &val); ++ dev_info(&client->dev, "Chip ID read result: ret=%d, val=0x%06x (expected 0x%06x)\n", ++ ret, val, OV13858_CHIP_ID); + if (ret) + return ret; + +@@ -1509,7 +1640,7 @@ + OV13858_CHIP_ID, val); + return -EIO; + } +- ++ dev_info(&client->dev, "Chip ID verified successfully!\n"); + return 0; + } + +@@ -1664,6 +1795,7 @@ + u32 val = 0; + + device_property_read_u32(&client->dev, "clock-frequency", &val); ++ dev_info(&client->dev, "Clock frequency read: %u (expected 19200000)\n", val); + if (val != 19200000) + return -EINVAL; + +@@ -1671,14 +1803,33 @@ + if (!ov13858) + return -ENOMEM; + ++ /* Get the external clock */ ++ ov13858->xvclk = devm_clk_get_optional(&client->dev, "xvclk"); ++ if (IS_ERR(ov13858->xvclk)) ++ return dev_err_probe(&client->dev, PTR_ERR(ov13858->xvclk), ++ "failed to get xvclk\n"); ++ + /* Initialize subdev */ + v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops); + ++ ret = ov13858_get_regulators(ov13858); ++ if (ret) ++ return dev_err_probe(&client->dev, ret, ++ "Error fetching regulators\n"); ++ ++ ret = ov13858_get_gpios(ov13858); ++ if (ret) ++ return ret; ++ ++ ret = ov13858_sensor_powerup(ov13858); ++ if (ret) ++ return ret; // No cleanup needed yet, devm handles GPIOs/regulators ++ + /* Check module identity */ + ret = ov13858_identify_module(ov13858); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d\n", ret); +- return ret; ++ goto error_power_off; // Now we need to power down + } + + /* Set default mode to max resolution */ +@@ -1686,7 +1837,7 @@ + + ret = ov13858_init_controls(ov13858); + if (ret) +- return ret; ++ goto error_power_off; + + /* Initialize subdev */ + ov13858->sd.internal_ops = &ov13858_internal_ops; +@@ -1722,6 +1873,9 @@ + + error_handler_free: + ov13858_free_controls(ov13858); ++ ++error_power_off: ++ ov13858_sensor_powerdown(ov13858); + dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + + return ret; +@@ -1737,6 +1891,9 @@ + ov13858_free_controls(ov13858); + + pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ ov13858_sensor_powerdown(ov13858); ++ pm_runtime_set_suspended(&client->dev); + } + + static const struct i2c_device_id ov13858_id_table[] = { +@@ -1758,6 +1915,7 @@ + static struct i2c_driver ov13858_i2c_driver = { + .driver = { + .name = "ov13858", ++ .pm = &ov13858_pm_ops, + .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), + }, + .probe = ov13858_probe, + +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -205,6 +205,14 @@ + *con_id = "dvdd"; + *gpio_flags = GPIO_ACTIVE_HIGH; + break; ++ case 0x08: /* Surface Pro 9 - additional power rail */ ++ *con_id = "pwr1"; ++ *gpio_flags = GPIO_ACTIVE_HIGH; ++ break; ++ case 0x10: /* Surface Pro 9 - secondary power rail */ ++ *con_id = "pwr2"; ++ *gpio_flags = GPIO_ACTIVE_HIGH; ++ break; + default: + *con_id = "unknown"; + *gpio_flags = GPIO_ACTIVE_HIGH; +@@ -307,6 +315,8 @@ + case INT3472_GPIO_TYPE_PRIVACY_LED: + case INT3472_GPIO_TYPE_POWER_ENABLE: + case INT3472_GPIO_TYPE_HANDSHAKE: ++ case 0x08: /* Surface Pro 9 power rails */ ++ case 0x10: + gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); + if (IS_ERR(gpio)) { + ret = PTR_ERR(gpio); +@@ -345,6 +355,19 @@ + err_msg = "Failed to map handshake to sensor\n"; + + break; ++ case 0x08: /* Surface Pro 9 - treat as power*/ ++ dev_info(int3472->dev, "GPIO type 0x%02x detected on pin 0x%02x\n", type, agpio->pin_table[0]); ++ dev_info(int3472->dev, " con_id=%s, flags=0x%x\n", con_id, gpio_flags); ++ ret = skl_int3472_register_regulator(int3472, gpio, ++ GPIO_REGULATOR_ENABLE_TIME, ++ con_id, NULL); ++ dev_info(int3472->dev, " register_regulator returned: %d\n", ret); ++ if (ret) { ++ dev_err(int3472->dev, "Failed to register type 0x02x: %d\n", type, ret); ++ } ++ break; ++ case 0x10: ++ break; + default: /* Never reached */ + ret = -EINVAL; + break; + From 20ec4a735d75131d16430de869d9687a43e7a681 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 11 Oct 2025 04:21:13 +0200 Subject: [PATCH 130/236] Update Arch Linux kernel to v6.17.1 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- pkg/arch/kernel/0007-surface-sam.patch | 2 +- .../kernel/0008-surface-sam-over-hid.patch | 2 +- pkg/arch/kernel/0009-surface-button.patch | 2 +- pkg/arch/kernel/0010-surface-typecover.patch | 2 +- pkg/arch/kernel/0011-surface-shutdown.patch | 2 +- pkg/arch/kernel/0012-surface-gpe.patch | 2 +- pkg/arch/kernel/0013-cameras.patch | 2 +- pkg/arch/kernel/0014-amd-gpio.patch | 2 +- pkg/arch/kernel/0015-rtc.patch | 2 +- pkg/arch/kernel/PKGBUILD | 73 ++-- pkg/arch/kernel/config | 386 +++++++++++++----- pkg/arch/kernel/surface.config | 2 +- 18 files changed, 340 insertions(+), 151 deletions(-) diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 050a3810f4..83770e7463 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.16/0001-secureboot.patch \ No newline at end of file +../../../patches/6.17/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3.patch b/pkg/arch/kernel/0002-surface3.patch index 81bf491408..647d418669 120000 --- a/pkg/arch/kernel/0002-surface3.patch +++ b/pkg/arch/kernel/0002-surface3.patch @@ -1 +1 @@ -../../../patches/6.16/0002-surface3.patch \ No newline at end of file +../../../patches/6.17/0002-surface3.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index 2365db75c3..8eff39c65b 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.16/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.17/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index e64c2193b7..e6965f8f99 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.16/0004-ath10k.patch \ No newline at end of file +../../../patches/6.17/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index 86d6a9ee26..369f11a8c3 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.16/0005-ipts.patch \ No newline at end of file +../../../patches/6.17/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index 153815084d..3c7e254ed2 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.16/0006-ithc.patch \ No newline at end of file +../../../patches/6.17/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch index 53b3165a25..53e981c842 120000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -1 +1 @@ -../../../patches/6.16/0007-surface-sam.patch \ No newline at end of file +../../../patches/6.17/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch index 23b25d9ed5..5658b9eae0 120000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -1 +1 @@ -../../../patches/6.16/0008-surface-sam-over-hid.patch \ No newline at end of file +../../../patches/6.17/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch index e47f028209..f66ee87442 120000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -1 +1 @@ -../../../patches/6.16/0009-surface-button.patch \ No newline at end of file +../../../patches/6.17/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch index 66b94b0f30..94a5d85ad3 120000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -1 +1 @@ -../../../patches/6.16/0010-surface-typecover.patch \ No newline at end of file +../../../patches/6.17/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch index 457d60b3e8..226bc9909f 120000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -1 +1 @@ -../../../patches/6.16/0011-surface-shutdown.patch \ No newline at end of file +../../../patches/6.17/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch index db761cbfc8..3c0d80faa3 120000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -1 +1 @@ -../../../patches/6.16/0012-surface-gpe.patch \ No newline at end of file +../../../patches/6.17/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch index 90eef5fd00..0bc0237e89 120000 --- a/pkg/arch/kernel/0013-cameras.patch +++ b/pkg/arch/kernel/0013-cameras.patch @@ -1 +1 @@ -../../../patches/6.16/0013-cameras.patch \ No newline at end of file +../../../patches/6.17/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch index 1d9ae12f3c..4bdec9445b 120000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -1 +1 @@ -../../../patches/6.16/0014-amd-gpio.patch \ No newline at end of file +../../../patches/6.17/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch index a81a0efb55..0f2b4686ce 120000 --- a/pkg/arch/kernel/0015-rtc.patch +++ b/pkg/arch/kernel/0015-rtc.patch @@ -1 +1 @@ -../../../patches/6.16/0015-rtc.patch \ No newline at end of file +../../../patches/6.17/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index c54d0bbc98..618101c0ab 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.16.9.arch1 +pkgver=6.17.1.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -19,6 +19,9 @@ makedepends=( git libelf perl + rust + rust-bindgen + rust-src tar xz python @@ -28,7 +31,10 @@ makedepends=( optdepends=('iptsd: Touchscreen support' 'linux-firmware: Firmware files for Linux' 'linux-firmware-marvell: Firmware files for Marvell WiFi / Bluetooth') -options=('!strip') +options=( + !debug + !strip +) _srcname=archlinux-linux source=( "$_srcname::git+https://github.com/archlinux/linux#tag=$_srctag" @@ -57,25 +63,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('0b4d356f46d3f7ed9550bde02582d923c54fec1e9711ae8652ec2883f25c70fc' - '746810cf2462423b7f680c5eec9236f71399c02501a58bba8871fab70e693815' +sha256sums=('647162133ecdbf0b829c8291d41a325ce32df79ad93d89302106773a0cac3c87' + '57786a01f3cfaeb696f79bf3b19996f7f787df3df8c6fbf6a9654aced518ec93' 'ee110be98c41a45302b2b81b037e3c4392ea7f142282e28400ac67b37455d42a' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '586a8ef0b697205949c1b34bd0682c58a8fe8aa1fd1eebfe8b3974726e2e8687' - 'df38a268cfe60e56204d0077c496eba68b5cbaaf7c61348c3e8d979438333dcd' - '5e3c0f9fe3ac37a691871ebcb28e131de92a60f85c8493472c0e3512921c94ee' - '98c97c77274d453401388092913bf94eaf4de43e352a1af3a413f05e9366bd90' - 'fbff043a27297e8ca799fd57922f517eefedf512fb9caca8cad4abe21ce06aa8' - 'c317a3bd310ed8a39d04e9531e512c986b6b53c47dcdba0ae7b9901ffa43feb4' - 'adfaba77c6e10dc5c7bf346af213cd0fd89b9e7c9411f1ded4a77c2aa9eca2f5' - 'f9044581ded23904891f19d29bafaa22f990899f57ab282edb1ea21468ba3736' - 'd694b9daeede5aa1a455018e1ec5c17ecda16b3f69ee24b269b6e13d55767e42' - 'fcdb74c0d76731c3a9e48952723696334931f11ea4f90688a826511742e72f79' - 'd98cd22320c7ef5a25c2869247f749d410dbbc699cb5eea391af395f7eae1324' - '4e3026416c2b6d090a2cb5d4ca90e48f1d12b754a89beedebab70b51ab0b8bdf' - 'e7de83a2c5c4bd812744c1e1a43e75fae5e105f5c9360c7b1bca3ce83bf8a761' - '4b649582d6dce4853bf39faac75ff103d8b8d62e9979e74a01f28f61fc043e54' - '34b70e5dad472978844a02d88bf64d49c81594e431729ec686e30c5a14eb7b8b') + '04ad5ce818a39165235d387d428aeb12605be8c5b1e913a0c7a12c9c5edef1c2' + '42f639c52f38defda3d5516859c1afc42aa3c162f8f8eb1cbae3677e2a41695f' + '3640e5db83140bb62e2183c69cc00bc00fbf22a1d96479481a2b65486f381218' + '83c63f25996736426892affda4f75f11dd5d176afa39ee7c52d19c109d9b6e97' + '4f0833e207090cef3dc8af42c28e42f91138a5fbbd52b3a21dfcde435fe5d352' + '7fda97124a4bbd20077617c9ebd27f550159a82de68c488c689efb19b7dd42ae' + '2ce4ddf8715ba5c406ba1143b2082268b6b3ba297b694944c826765340783afe' + '79a81118886c06aa35a9963ce39d97bf996cdfae2d35089ba3075c1e7fd2d9b3' + '172a6b04b90885f0edd7609b287a534061c639a746c3b7eaf1994df81e7e9084' + '43c82fbb7583be29d2e49447e7ee1860745d5cfe2af3fd1439aacbe4aee84522' + '10756fbb38b21e4c886826c29b042028a42d42cc064178a53a8389b3945cadf9' + '8ef4848edcfd3a284e9a69d297b303023dda27b8482cbd5d7f67a8e59082da1c' + '4e893decdb56341e542bc4aed20c9507670e4a68b732cc638bd93ad2ef18b16b' + 'e46a3593f44b32eb8ef9295412e912716a676eb42d066a65d643ac6b3d6b7ce4' + '5660ab754f3ce5ac0a0af746b93b573322f9e940a8ab6f0890aae2e38a86e181') export KBUILD_BUILD_HOST=archlinux @@ -126,6 +132,7 @@ prepare() { build() { cd $_srcname _make all + _make -C tools/bpf/bpftool vmlinux.h feature-clang-bpf-co-re=1 } _package() { @@ -136,12 +143,14 @@ _package() { kmod ) optdepends=( - 'wireless-regdb: to set the correct wireless channels of your country' 'linux-firmware: firmware images needed for some devices' + 'scx-scheds: to use sched-ext schedulers' + 'wireless-regdb: to set the correct wireless channels of your country' ) provides=( linux=${_shortver} KSMBD-MODULE + NTSYNC-MODULE VIRTUALBOX-GUEST-MODULES WIREGUARD-MODULE ) @@ -169,10 +178,10 @@ _package() { echo "$pkgbase" | install -Dm644 /dev/stdin "$modulesdir/pkgbase" echo "Installing modules..." - _make INSTALL_MOD_PATH="$pkgdir/usr" INSTALL_MOD_STRIP=1 \ + ZSTD_CLEVEL=19 _make INSTALL_MOD_PATH="$pkgdir/usr" INSTALL_MOD_STRIP=1 \ DEPMOD=/doesnt/exist modules_install # Suppress depmod - # remove build and source links + # remove build link rm "$modulesdir"/build } @@ -186,14 +195,18 @@ _package-headers() { echo "Installing build files..." install -Dt "$builddir" -m644 .config Makefile Module.symvers System.map \ - localversion.* version vmlinux + localversion.* version vmlinux tools/bpf/bpftool/vmlinux.h install -Dt "$builddir/kernel" -m644 kernel/Makefile install -Dt "$builddir/arch/x86" -m644 arch/x86/Makefile cp -t "$builddir" -a scripts + ln -srt "$builddir" "$builddir/scripts/gdb/vmlinux-gdb.py" # required when STACK_VALIDATION is enabled install -Dt "$builddir/tools/objtool" tools/objtool/objtool + # required when DEBUG_INFO_BTF_MODULES is enabled + install -Dt "$builddir/tools/bpf/resolve_btfids" tools/bpf/resolve_btfids/resolve_btfids + echo "Installing headers..." cp -t "$builddir" -a include cp -t "$builddir/arch/x86" -a arch/x86/include @@ -202,10 +215,10 @@ _package-headers() { install -Dt "$builddir/drivers/md" -m644 drivers/md/*.h install -Dt "$builddir/net/mac80211" -m644 net/mac80211/*.h - # http://bugs.archlinux.org/task/13146 + # https://bugs.archlinux.org/task/13146 install -Dt "$builddir/drivers/media/i2c" -m644 drivers/media/i2c/msp3400-driver.h - # http://bugs.archlinux.org/task/20402 + # https://bugs.archlinux.org/task/20402 install -Dt "$builddir/drivers/media/usb/dvb-usb" -m644 drivers/media/usb/dvb-usb/*.h install -Dt "$builddir/drivers/media/dvb-frontends" -m644 drivers/media/dvb-frontends/*.h install -Dt "$builddir/drivers/media/tuners" -m644 drivers/media/tuners/*.h @@ -216,6 +229,14 @@ _package-headers() { echo "Installing KConfig files..." find . -name 'Kconfig*' -exec install -Dm644 {} "$builddir/{}" \; + echo "Installing Rust files..." + install -Dt "$builddir/rust" -m644 rust/*.rmeta + install -Dt "$builddir/rust" rust/*.so + + echo "Installing unstripped VDSO..." + make INSTALL_MOD_PATH="$pkgdir/usr" vdso_install \ + link= # Suppress build-id symlinks + echo "Removing unneeded architectures..." local arch for arch in "$builddir"/arch/*/; do @@ -236,7 +257,7 @@ _package-headers() { echo "Stripping build tools..." local file while read -rd '' file; do - case "$(file -bi "$file")" in + case "$(file -Sib "$file")" in application/x-sharedlib\;*) # Libraries (.so) strip -v $STRIP_SHARED "$file" ;; application/x-archive\;*) # Libraries (.a) diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index eb0d9e52f9..236d97838a 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.16.9-arch1 Kernel Configuration +# Linux/x86 6.17.1-arch1 Kernel Configuration # CONFIG_CC_VERSION_TEXT="gcc (GCC) 15.2.1 20250813" CONFIG_CC_IS_GCC=y @@ -26,6 +26,7 @@ CONFIG_LD_CAN_USE_KEEP_IN_OVERLAY=y CONFIG_RUSTC_HAS_COERCE_POINTEE=y CONFIG_RUSTC_HAS_SPAN_FILE=y CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES=y +CONFIG_RUSTC_HAS_FILE_WITH_NUL=y CONFIG_PAHOLE_VERSION=130 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y @@ -116,6 +117,7 @@ CONFIG_CONTEXT_TRACKING_USER=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100 +CONFIG_POSIX_AUX_CLOCKS=y # end of Timers subsystem CONFIG_BPF=y @@ -233,6 +235,7 @@ CONFIG_BLK_CGROUP=y CONFIG_CGROUP_WRITEBACK=y CONFIG_CGROUP_SCHED=y CONFIG_GROUP_SCHED_WEIGHT=y +CONFIG_GROUP_SCHED_BANDWIDTH=y CONFIG_FAIR_GROUP_SCHED=y CONFIG_CFS_BANDWIDTH=y # CONFIG_RT_GROUP_SCHED is not set @@ -297,6 +300,7 @@ CONFIG_ELF_CORE=y CONFIG_PCSPKR_PLATFORM=y CONFIG_FUTEX=y CONFIG_FUTEX_PI=y +CONFIG_FUTEX_PRIVATE_HASH=y CONFIG_FUTEX_MPOL=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y @@ -824,6 +828,7 @@ CONFIG_KVM_INTEL=m CONFIG_X86_SGX_KVM=y CONFIG_KVM_AMD=m CONFIG_KVM_AMD_SEV=y +CONFIG_KVM_IOAPIC=y CONFIG_KVM_SMM=y CONFIG_KVM_HYPERV=y CONFIG_KVM_XEN=y @@ -863,6 +868,8 @@ CONFIG_HOTPLUG_CORE_SYNC_DEAD=y CONFIG_HOTPLUG_CORE_SYNC_FULL=y CONFIG_HOTPLUG_SPLIT_STARTUP=y CONFIG_HOTPLUG_PARALLEL=y +CONFIG_GENERIC_IRQ_ENTRY=y +CONFIG_GENERIC_SYSCALL=y CONFIG_GENERIC_ENTRY=y CONFIG_KPROBES=y CONFIG_JUMP_LABEL=y @@ -929,7 +936,7 @@ CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_SECCOMP=y CONFIG_SECCOMP_FILTER=y # CONFIG_SECCOMP_CACHE_DEBUG is not set -CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_ARCH_KSTACK_ERASE=y CONFIG_HAVE_STACKPROTECTOR=y CONFIG_STACKPROTECTOR=y CONFIG_STACKPROTECTOR_STRONG=y @@ -1028,6 +1035,7 @@ CONFIG_FUNCTION_ALIGNMENT_16B=y CONFIG_FUNCTION_ALIGNMENT=16 CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT=y CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y +CONFIG_ARCH_HAS_CPU_ATTACK_VECTORS=y # end of General architecture-dependent options CONFIG_RT_MUTEXES=y @@ -1259,7 +1267,7 @@ CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_CMA_SYSFS=y CONFIG_CMA_AREAS=7 -CONFIG_PAGE_BLOCK_ORDER=10 +CONFIG_PAGE_BLOCK_MAX_ORDER=10 CONFIG_MEM_SOFT_DIRTY=y CONFIG_GENERIC_EARLY_IOREMAP=y # CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set @@ -1267,7 +1275,6 @@ CONFIG_PAGE_IDLE_FLAG=y CONFIG_IDLE_PAGE_TRACKING=y CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y -CONFIG_ARCH_HAS_PTE_DEVMAP=y CONFIG_ZONE_DMA=y CONFIG_ZONE_DMA32=y CONFIG_ZONE_DEVICE=y @@ -1315,6 +1322,8 @@ CONFIG_DAMON_PADDR=y CONFIG_DAMON_SYSFS=y CONFIG_DAMON_RECLAIM=y CONFIG_DAMON_LRU_SORT=y +CONFIG_DAMON_STAT=y +# CONFIG_DAMON_STAT_ENABLED_DEFAULT is not set # end of Data Access Monitoring # end of Memory Management options @@ -1492,7 +1501,6 @@ CONFIG_NF_CONNTRACK_TIMEOUT=y CONFIG_NF_CONNTRACK_TIMESTAMP=y CONFIG_NF_CONNTRACK_LABELS=y CONFIG_NF_CONNTRACK_OVS=y -CONFIG_NF_CT_PROTO_DCCP=y CONFIG_NF_CT_PROTO_GRE=y CONFIG_NF_CT_PROTO_SCTP=y CONFIG_NF_CT_PROTO_UDPLITE=y @@ -1526,6 +1534,7 @@ CONFIG_NF_TABLES_INET=y CONFIG_NF_TABLES_NETDEV=y CONFIG_NFT_NUMGEN=m CONFIG_NFT_CT=m +# CONFIG_NFT_EXTHDR_DCCP is not set CONFIG_NFT_FLOW_OFFLOAD=m CONFIG_NFT_CONNLIMIT=m CONFIG_NFT_LOG=m @@ -1557,6 +1566,7 @@ CONFIG_NF_FLOW_TABLE=m CONFIG_NF_FLOW_TABLE_PROCFS=y CONFIG_NETFILTER_XTABLES=m CONFIG_NETFILTER_XTABLES_COMPAT=y +CONFIG_NETFILTER_XTABLES_LEGACY=y # # Xtables combined modules @@ -1863,6 +1873,7 @@ CONFIG_NET_DSA_TAG_AR9331=m CONFIG_NET_DSA_TAG_BRCM_COMMON=m CONFIG_NET_DSA_TAG_BRCM=m CONFIG_NET_DSA_TAG_BRCM_LEGACY=m +CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS=m CONFIG_NET_DSA_TAG_BRCM_PREPEND=m CONFIG_NET_DSA_TAG_HELLCREEK=m CONFIG_NET_DSA_TAG_GSWIP=m @@ -1948,6 +1959,7 @@ CONFIG_NET_SCH_INGRESS=m CONFIG_NET_SCH_PLUG=m CONFIG_NET_SCH_ETS=m CONFIG_NET_SCH_BPF=y +CONFIG_NET_SCH_DUALPI2=m CONFIG_NET_SCH_DEFAULT=y # CONFIG_DEFAULT_FQ is not set # CONFIG_DEFAULT_CODEL is not set @@ -2531,8 +2543,10 @@ CONFIG_EFI_EARLYCON=y CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y # CONFIG_EFI_DISABLE_RUNTIME is not set CONFIG_EFI_COCO_SECRET=y +CONFIG_OVMF_DEBUG_LOG=y CONFIG_UNACCEPTED_MEMORY=y CONFIG_EFI_EMBEDDED_FIRMWARE=y +CONFIG_EFI_SBAT_FILE="" # end of EFI (Extensible Firmware Interface) Support CONFIG_UEFI_CPER=y @@ -2630,6 +2644,7 @@ CONFIG_MTD_MTDRAM=m CONFIG_MTDRAM_TOTAL_SIZE=4096 CONFIG_MTDRAM_ERASE_SIZE=128 CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_INTEL_DG=m # # Disk-On-Chip Device Drivers @@ -2742,9 +2757,6 @@ CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_CDROM_PKTCDVD=m -CONFIG_CDROM_PKTCDVD_BUFFERS=8 -# CONFIG_CDROM_PKTCDVD_WCACHE is not set CONFIG_ATA_OVER_ETH=m CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_BLKDEV_BACKEND=m @@ -3402,6 +3414,7 @@ CONFIG_BNXT_SRIOV=y CONFIG_BNXT_FLOWER_OFFLOAD=y CONFIG_BNXT_DCB=y CONFIG_BNXT_HWMON=y +CONFIG_BNGE=m CONFIG_NET_VENDOR_CADENCE=y CONFIG_MACB=m CONFIG_MACB_USE_HWSTAMP=y @@ -3448,6 +3461,8 @@ CONFIG_ULI526X=m CONFIG_PCMCIA_XIRCOM=m CONFIG_NET_VENDOR_DLINK=y CONFIG_DL2K=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set CONFIG_NET_VENDOR_EMULEX=y CONFIG_BE2NET=m CONFIG_BE2NET_HWMON=y @@ -3475,6 +3490,7 @@ CONFIG_NET_VENDOR_I825XX=y CONFIG_NET_VENDOR_INTEL=y CONFIG_LIBETH=m CONFIG_LIBIE=m +CONFIG_LIBIE_ADMINQ=m CONFIG_E100=m CONFIG_E1000=m CONFIG_E1000E=m @@ -3697,6 +3713,8 @@ CONFIG_NET_VENDOR_WANGXUN=y CONFIG_LIBWX=m CONFIG_NGBE=m CONFIG_TXGBE=m +CONFIG_TXGBEVF=m +CONFIG_NGBEVF=m CONFIG_NET_VENDOR_WIZNET=y CONFIG_WIZNET_W5100=m CONFIG_WIZNET_W5300=m @@ -3717,6 +3735,7 @@ CONFIG_SKFP=m CONFIG_PHYLINK=m CONFIG_PHYLIB=m CONFIG_SWPHY=y +CONFIG_PHY_PACKAGE=m CONFIG_LED_TRIGGER_PHY=y CONFIG_OPEN_ALLIANCE_HELPERS=y CONFIG_FIXED_PHY=m @@ -4264,6 +4283,7 @@ CONFIG_RTW88_LEDS=y CONFIG_RTW89=m CONFIG_RTW89_CORE=m CONFIG_RTW89_PCI=m +CONFIG_RTW89_USB=m CONFIG_RTW89_8851B=m CONFIG_RTW89_8852A=m CONFIG_RTW89_8852B_COMMON=m @@ -4272,8 +4292,10 @@ CONFIG_RTW89_8852BT=m CONFIG_RTW89_8852C=m CONFIG_RTW89_8922A=m CONFIG_RTW89_8851BE=m +CONFIG_RTW89_8851BU=m CONFIG_RTW89_8852AE=m CONFIG_RTW89_8852BE=m +CONFIG_RTW89_8852BU=m CONFIG_RTW89_8852BTE=m CONFIG_RTW89_8852CE=m CONFIG_RTW89_8922AE=m @@ -4390,7 +4412,6 @@ CONFIG_INPUT_KEYBOARD=y CONFIG_KEYBOARD_ADC=m CONFIG_KEYBOARD_ADP5520=m CONFIG_KEYBOARD_ADP5588=m -CONFIG_KEYBOARD_ADP5589=m CONFIG_KEYBOARD_APPLESPI=m CONFIG_KEYBOARD_ATKBD=y CONFIG_KEYBOARD_QT1050=m @@ -4676,6 +4697,8 @@ CONFIG_RMI4_F03_SERIO=m CONFIG_RMI4_2D_SENSOR=y CONFIG_RMI4_F11=y CONFIG_RMI4_F12=y +CONFIG_RMI4_F1A=y +CONFIG_RMI4_F21=y CONFIG_RMI4_F30=y CONFIG_RMI4_F34=y CONFIG_RMI4_F3A=y @@ -5037,6 +5060,7 @@ CONFIG_SPI_DYNAMIC=y # # SPI Offload triggers # +CONFIG_SPI_OFFLOAD_TRIGGER_ADI_UTIL_SD=m CONFIG_SPI_OFFLOAD_TRIGGER_PWM=m # CONFIG_SPMI is not set # CONFIG_HSI is not set @@ -5072,6 +5096,15 @@ CONFIG_PTP_1588_CLOCK_OCP=m CONFIG_PTP_DFL_TOD=m # end of PTP clock support +# +# DPLL device support +# +CONFIG_DPLL=y +CONFIG_ZL3073X=m +CONFIG_ZL3073X_I2C=m +CONFIG_ZL3073X_SPI=m +# end of DPLL device support + CONFIG_PINCTRL=y CONFIG_PINMUX=y CONFIG_PINCONF=y @@ -5124,6 +5157,7 @@ CONFIG_PINCTRL_TIGERLAKE=m # # end of Renesas pinctrl drivers +CONFIG_GPIOLIB_LEGACY=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_FASTPATH_LIMIT=512 CONFIG_GPIO_ACPI=y @@ -5201,7 +5235,7 @@ CONFIG_GPIO_LJCA=m CONFIG_GPIO_LP3943=m CONFIG_GPIO_LP873X=m CONFIG_GPIO_MADERA=m -CONFIG_GPIO_PALMAS=y +CONFIG_GPIO_PALMAS=m CONFIG_GPIO_RC5T583=y CONFIG_GPIO_TPS65086=m CONFIG_GPIO_TPS6586X=y @@ -5553,6 +5587,7 @@ CONFIG_SENSORS_ACBEL_FSG032=m CONFIG_SENSORS_ADM1266=m CONFIG_SENSORS_ADM1275=m CONFIG_SENSORS_ADP1050=m +CONFIG_SENSORS_ADP1050_REGULATOR=y CONFIG_SENSORS_BEL_PFE=m CONFIG_SENSORS_BPA_RS600=m CONFIG_SENSORS_CRPS=m @@ -5876,6 +5911,9 @@ CONFIG_MFD_AXP20X=m CONFIG_MFD_AXP20X_I2C=m CONFIG_MFD_CGBC=m CONFIG_MFD_CROS_EC_DEV=m +CONFIG_MFD_CS40L50_CORE=m +CONFIG_MFD_CS40L50_I2C=m +CONFIG_MFD_CS40L50_SPI=m CONFIG_MFD_CS42L43=m CONFIG_MFD_CS42L43_I2C=m CONFIG_MFD_CS42L43_SDW=m @@ -5990,9 +6028,6 @@ CONFIG_MFD_WM8994=m CONFIG_MFD_WCD934X=m CONFIG_MFD_ATC260X=m CONFIG_MFD_ATC260X_I2C=m -CONFIG_MFD_CS40L50_CORE=m -CONFIG_MFD_CS40L50_I2C=m -CONFIG_MFD_CS40L50_SPI=m CONFIG_RAVE_SP_CORE=m CONFIG_MFD_INTEL_M10_BMC_CORE=m CONFIG_MFD_INTEL_M10_BMC_SPI=m @@ -6732,16 +6767,13 @@ CONFIG_VIDEO_ET8EK8=m CONFIG_VIDEO_THP7312=m # end of Camera ISPs -# -# Lens drivers -# +CONFIG_VIDEO_CAMERA_LENS=y CONFIG_VIDEO_AD5820=m CONFIG_VIDEO_AK7375=m CONFIG_VIDEO_DW9714=m CONFIG_VIDEO_DW9719=m CONFIG_VIDEO_DW9768=m CONFIG_VIDEO_DW9807_VCM=m -# end of Lens drivers # # Flash devices @@ -6789,6 +6821,7 @@ CONFIG_VIDEO_M52790=m # # Video serializers and deserializers # +CONFIG_VIDEO_MAX96717=m # end of Video serializers and deserializers # @@ -7067,6 +7100,7 @@ CONFIG_DRM_DISPLAY_DP_HELPER=y CONFIG_DRM_DISPLAY_DP_TUNNEL=y CONFIG_DRM_DISPLAY_DSC_HELPER=y CONFIG_DRM_DISPLAY_HDCP_HELPER=y +CONFIG_DRM_DISPLAY_HDMI_CEC_NOTIFIER_HELPER=y CONFIG_DRM_DISPLAY_HDMI_HELPER=y CONFIG_DRM_TTM=m CONFIG_DRM_EXEC=m @@ -7150,7 +7184,7 @@ CONFIG_DRM_XE=m CONFIG_DRM_XE_DISPLAY=y CONFIG_DRM_XE_DP_TUNNEL=y CONFIG_DRM_XE_GPUSVM=y -CONFIG_DRM_XE_DEVMEM_MIRROR=y +CONFIG_DRM_XE_PAGEMAP=y CONFIG_DRM_XE_FORCE_PROBE="" CONFIG_DRM_XE_JOB_TIMEOUT_MAX=10000 CONFIG_DRM_XE_JOB_TIMEOUT_MIN=1 @@ -7275,7 +7309,6 @@ CONFIG_XEN_FBDEV_FRONTEND=m # CONFIG_FB_SM712 is not set CONFIG_FB_CORE=y CONFIG_FB_NOTIFY=y -# CONFIG_FIRMWARE_EDID is not set CONFIG_FB_DEVICE=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y @@ -7350,6 +7383,7 @@ CONFIG_BACKLIGHT_RAVE_SP=m CONFIG_VIDEOMODE_HELPERS=y CONFIG_HDMI=y +# CONFIG_FIRMWARE_EDID is not set # # Console display driver support @@ -7366,6 +7400,7 @@ CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y # end of Console display driver support # CONFIG_LOGO is not set +CONFIG_TRACE_GPU_MEM=y # end of Graphics support CONFIG_DRM_ACCEL=y @@ -7520,55 +7555,76 @@ CONFIG_SND_YMFPCI=m # HD-Audio # CONFIG_SND_HDA=m -CONFIG_SND_HDA_GENERIC_LEDS=y -CONFIG_SND_HDA_INTEL=m -CONFIG_SND_HDA_ACPI=m CONFIG_SND_HDA_HWDEP=y CONFIG_SND_HDA_RECONFIG=y CONFIG_SND_HDA_INPUT_BEEP=y CONFIG_SND_HDA_INPUT_BEEP_MODE=0 CONFIG_SND_HDA_PATCH_LOADER=y -CONFIG_SND_HDA_CIRRUS_SCODEC=m -CONFIG_SND_HDA_SCODEC_CS35L41=m -CONFIG_SND_HDA_SCODEC_COMPONENT=m -CONFIG_SND_HDA_SCODEC_CS35L41_I2C=m -CONFIG_SND_HDA_SCODEC_CS35L41_SPI=m -CONFIG_SND_HDA_SCODEC_CS35L56=m -CONFIG_SND_HDA_SCODEC_CS35L56_I2C=m -CONFIG_SND_HDA_SCODEC_CS35L56_SPI=m -CONFIG_SND_HDA_SCODEC_TAS2781=m -CONFIG_SND_HDA_SCODEC_TAS2781_I2C=m -CONFIG_SND_HDA_SCODEC_TAS2781_SPI=m -CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=10 +# CONFIG_SND_HDA_CTL_DEV_ID is not set +CONFIG_SND_HDA_PREALLOC_SIZE=0 +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_ACPI=m +CONFIG_SND_HDA_GENERIC_LEDS=y CONFIG_SND_HDA_CODEC_ANALOG=m CONFIG_SND_HDA_CODEC_SIGMATEL=m CONFIG_SND_HDA_CODEC_VIA=m -CONFIG_SND_HDA_CODEC_HDMI=m -CONFIG_SND_HDA_CODEC_CIRRUS=m -CONFIG_SND_HDA_CODEC_CS8409=m CONFIG_SND_HDA_CODEC_CONEXANT=m CONFIG_SND_HDA_CODEC_SENARYTECH=m CONFIG_SND_HDA_CODEC_CA0110=m CONFIG_SND_HDA_CODEC_CA0132=m CONFIG_SND_HDA_CODEC_CA0132_DSP=y CONFIG_SND_HDA_CODEC_CMEDIA=m +CONFIG_SND_HDA_CODEC_CM9825=m CONFIG_SND_HDA_CODEC_SI3054=m CONFIG_SND_HDA_GENERIC=m -CONFIG_SND_HDA_POWER_SAVE_DEFAULT=10 +CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_CODEC_REALTEK_LIB=m +CONFIG_SND_HDA_CODEC_ALC260=m +CONFIG_SND_HDA_CODEC_ALC262=m +CONFIG_SND_HDA_CODEC_ALC268=m +CONFIG_SND_HDA_CODEC_ALC269=m +CONFIG_SND_HDA_CODEC_ALC662=m +CONFIG_SND_HDA_CODEC_ALC680=m +CONFIG_SND_HDA_CODEC_ALC861=m +CONFIG_SND_HDA_CODEC_ALC861VD=m +CONFIG_SND_HDA_CODEC_ALC880=m +CONFIG_SND_HDA_CODEC_ALC882=m +CONFIG_SND_HDA_CODEC_CIRRUS=m +CONFIG_SND_HDA_CODEC_CS420X=m +CONFIG_SND_HDA_CODEC_CS421X=m +CONFIG_SND_HDA_CODEC_CS8409=m +CONFIG_SND_HDA_CODEC_HDMI=m +CONFIG_SND_HDA_CODEC_HDMI_GENERIC=m +CONFIG_SND_HDA_CODEC_HDMI_SIMPLE=m +CONFIG_SND_HDA_CODEC_HDMI_INTEL=m CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM=y -# CONFIG_SND_HDA_CTL_DEV_ID is not set -# end of HD-Audio - +CONFIG_SND_HDA_CODEC_HDMI_ATI=m +CONFIG_SND_HDA_CODEC_HDMI_NVIDIA=m +CONFIG_SND_HDA_CODEC_HDMI_NVIDIA_MCP=m +CONFIG_SND_HDA_CODEC_HDMI_TEGRA=m +CONFIG_SND_HDA_CIRRUS_SCODEC=m +CONFIG_SND_HDA_SCODEC_CS35L41=m +CONFIG_SND_HDA_SCODEC_COMPONENT=m +CONFIG_SND_HDA_SCODEC_CS35L41_I2C=m +CONFIG_SND_HDA_SCODEC_CS35L41_SPI=m +CONFIG_SND_HDA_SCODEC_CS35L56=m +CONFIG_SND_HDA_SCODEC_CS35L56_I2C=m +CONFIG_SND_HDA_SCODEC_CS35L56_SPI=m +CONFIG_SND_HDA_SCODEC_TAS2781=m +CONFIG_SND_HDA_SCODEC_TAS2781_I2C=m +CONFIG_SND_HDA_SCODEC_TAS2781_SPI=m CONFIG_SND_HDA_CORE=m CONFIG_SND_HDA_DSP_LOADER=y CONFIG_SND_HDA_COMPONENT=y CONFIG_SND_HDA_I915=y CONFIG_SND_HDA_EXT_CORE=m -CONFIG_SND_HDA_PREALLOC_SIZE=0 CONFIG_SND_INTEL_NHLT=y CONFIG_SND_INTEL_DSP_CONFIG=m CONFIG_SND_INTEL_SOUNDWIRE_ACPI=m # CONFIG_SND_INTEL_BYT_PREFER_SOF is not set +# end of HD-Audio + CONFIG_SND_SPI=y CONFIG_SND_USB=y CONFIG_SND_USB_AUDIO=m @@ -7609,9 +7665,17 @@ CONFIG_SND_SOC_COMPRESS=y CONFIG_SND_SOC_TOPOLOGY=y CONFIG_SND_SOC_ACPI=m CONFIG_SND_SOC_USB=m -CONFIG_SND_SOC_ADI=m + +# +# Analog Devices +# CONFIG_SND_SOC_ADI_AXI_I2S=m CONFIG_SND_SOC_ADI_AXI_SPDIF=m +# end of Analog Devices + +# +# AMD +# CONFIG_SND_SOC_AMD_ACP=m CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH=m CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m @@ -7650,13 +7714,43 @@ CONFIG_SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE=m CONFIG_SND_SOC_AMD_SOUNDWIRE=m CONFIG_SND_SOC_AMD_PS=m CONFIG_SND_SOC_AMD_PS_MACH=m -CONFIG_SND_ATMEL_SOC=m +# end of AMD + +# +# Apple +# +# end of Apple + +# +# Atmel +# +# end of Atmel + +# +# Au1x +# +# end of Au1x + +# +# Broadcom +# # CONFIG_SND_BCM63XX_I2S_WHISTLER is not set +# end of Broadcom + +# +# Cirrus Logic +# +# end of Cirrus Logic + +# +# DesignWare +# CONFIG_SND_DESIGNWARE_I2S=m CONFIG_SND_DESIGNWARE_PCM=y +# end of DesignWare # -# SoC Audio for Freescale CPUs +# Freescale # # @@ -7672,23 +7766,38 @@ CONFIG_SND_DESIGNWARE_PCM=y CONFIG_SND_SOC_FSL_XCVR=m CONFIG_SND_SOC_FSL_UTILS=m # CONFIG_SND_SOC_IMX_AUDMUX is not set -# end of SoC Audio for Freescale CPUs +# end of Freescale +# +# Google +# CONFIG_SND_SOC_CHV3_I2S=m +# end of Google + +# +# Hisilicon +# CONFIG_SND_I2S_HI6210_I2S=m +# end of Hisilicon + +# +# JZ4740 +# +# end of JZ4740 + +# +# Kirkwood +# +# end of Kirkwood # -# SoC Audio for Loongson CPUs +# Loongson # -# end of SoC Audio for Loongson CPUs +# end of Loongson -CONFIG_SND_SOC_IMG=y -CONFIG_SND_SOC_IMG_I2S_IN=m -CONFIG_SND_SOC_IMG_I2S_OUT=m -CONFIG_SND_SOC_IMG_PARALLEL_OUT=m -CONFIG_SND_SOC_IMG_SPDIF_IN=m -CONFIG_SND_SOC_IMG_SPDIF_OUT=m -CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC=m +# +# Intel +# CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y CONFIG_SND_SOC_INTEL_CATPT=m CONFIG_SND_SST_ATOM_HIFI2_PLATFORM=m @@ -7721,6 +7830,7 @@ CONFIG_SND_SOC_INTEL_AVS_MACH_RT274=m CONFIG_SND_SOC_INTEL_AVS_MACH_RT286=m CONFIG_SND_SOC_INTEL_AVS_MACH_RT298=m CONFIG_SND_SOC_INTEL_AVS_MACH_RT5514=m +CONFIG_SND_SOC_INTEL_AVS_MACH_RT5640=m CONFIG_SND_SOC_INTEL_AVS_MACH_RT5663=m CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682=m CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567=m @@ -7764,9 +7874,62 @@ CONFIG_SND_SOC_INTEL_SOF_DA7219_MACH=m CONFIG_SND_SOC_INTEL_SOF_SSP_AMP_MACH=m CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH=m CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH=m +# end of Intel + +# +# Mediatek +# CONFIG_SND_SOC_MTK_BTCVSD=m +# end of Mediatek + +# +# PXA +# +# end of PXA + +# +# SoundWire (SDCA) +# CONFIG_SND_SOC_SDCA=m +CONFIG_SND_SOC_SDCA_HID=y +CONFIG_SND_SOC_SDCA_IRQ=y CONFIG_SND_SOC_SDCA_OPTIONAL=m +# end of SoundWire (SDCA) + +# +# ST SPEAr +# +# end of ST SPEAr + +# +# Spreadtrum +# +# end of Spreadtrum + +# +# STMicroelectronics STM32 +# +# end of STMicroelectronics STM32 + +# +# Tegra +# +# end of Tegra + +# +# Xilinx +# +CONFIG_SND_SOC_XILINX_I2S=m +CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER=m +CONFIG_SND_SOC_XILINX_SPDIF=m +# end of Xilinx + +# +# Xtensa +# +CONFIG_SND_SOC_XTFPGA_I2S=m +# end of Xtensa + CONFIG_SND_SOC_SOF_TOPLEVEL=y CONFIG_SND_SOC_SOF_PCI_DEV=m CONFIG_SND_SOC_SOF_PCI=m @@ -7829,16 +7992,6 @@ CONFIG_SND_SOC_SOF_HDA_PROBES=m CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE=m CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE=m CONFIG_SND_SOC_SOF_XTENSA=m - -# -# STMicroelectronics STM32 SOC audio support -# -# end of STMicroelectronics STM32 SOC audio support - -CONFIG_SND_SOC_XILINX_I2S=m -CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER=m -CONFIG_SND_SOC_XILINX_SPDIF=m -CONFIG_SND_SOC_XTFPGA_I2S=m CONFIG_SND_SOC_I2C_AND_SPI=m # @@ -8037,6 +8190,7 @@ CONFIG_SND_SOC_RT715_SDCA_SDW=m CONFIG_SND_SOC_RT9120=m CONFIG_SND_SOC_RT9123=m CONFIG_SND_SOC_RT9123P=m +CONFIG_SND_SOC_RTQ9124=m CONFIG_SND_SOC_RTQ9128=m # CONFIG_SND_SOC_SDW_MOCKUP is not set CONFIG_SND_SOC_SGTL5000=m @@ -8162,8 +8316,14 @@ CONFIG_SND_SOC_LPASS_TX_MACRO=m # end of CODEC drivers CONFIG_SND_SOC_SDW_UTILS=m + +# +# Generic drivers +# CONFIG_SND_SIMPLE_CARD_UTILS=m CONFIG_SND_SIMPLE_CARD=m +# end of Generic drivers + CONFIG_SND_X86=y CONFIG_HDMI_LPE_AUDIO=m CONFIG_SND_SYNTH_EMUX=m @@ -9013,8 +9173,6 @@ CONFIG_INFINIBAND_MTHCA=m CONFIG_INFINIBAND_MTHCA_DEBUG=y CONFIG_INFINIBAND_OCRDMA=m CONFIG_INFINIBAND_QEDR=m -CONFIG_INFINIBAND_QIB=m -CONFIG_INFINIBAND_QIB_DCA=y CONFIG_INFINIBAND_USNIC=m CONFIG_INFINIBAND_VMWARE_PVRDMA=m CONFIG_INFINIBAND_RDMAVT=m @@ -9102,7 +9260,6 @@ CONFIG_RTC_DRV_ISL1208=m CONFIG_RTC_DRV_ISL12022=m CONFIG_RTC_DRV_X1205=m CONFIG_RTC_DRV_PCF8523=m -CONFIG_RTC_DRV_PCF85063=m CONFIG_RTC_DRV_PCF85363=m CONFIG_RTC_DRV_PCF8563=m CONFIG_RTC_DRV_PCF8583=m @@ -9152,6 +9309,7 @@ CONFIG_RTC_I2C_AND_SPI=y CONFIG_RTC_DRV_DS3232=m CONFIG_RTC_DRV_DS3232_HWMON=y CONFIG_RTC_DRV_PCF2127=m +CONFIG_RTC_DRV_PCF85063=m CONFIG_RTC_DRV_RV3029C2=m CONFIG_RTC_DRV_RV3029_HWMON=y CONFIG_RTC_DRV_RX6110=m @@ -9252,6 +9410,7 @@ CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_SYSFS_STATS=y CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_CMA_LEGACY=y # end of DMABUF options CONFIG_DCA=m @@ -9451,6 +9610,7 @@ CONFIG_DVB_AV7110=m CONFIG_DVB_AV7110_OSD=y CONFIG_DVB_SP8870=m CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_INTEL_IPU7=m # # StarFive media platform drivers @@ -9530,14 +9690,13 @@ CONFIG_SURFACE_AGGREGATOR_BUS=y # CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set CONFIG_X86_PLATFORM_DEVICES=y CONFIG_ACPI_WMI=m +# CONFIG_ACPI_WMI_LEGACY_DEVICE_NAMES is not set CONFIG_WMI_BMOF=m CONFIG_HUAWEI_WMI=m CONFIG_MXM_WMI=m CONFIG_NVIDIA_WMI_EC_BACKLIGHT=m CONFIG_XIAOMI_WMI=m CONFIG_GIGABYTE_WMI=m -CONFIG_YOGABOOK=m -CONFIG_YT2_1380=m CONFIG_ACERHDF=m CONFIG_ACER_WIRELESS=m CONFIG_ACER_WMI=m @@ -9554,6 +9713,7 @@ CONFIG_AMD_PMF=m # CONFIG_AMD_PMF_DEBUG is not set CONFIG_AMD_PMC=m CONFIG_AMD_MP2_STB=y +CONFIG_AMD_HFI=y CONFIG_AMD_3D_VCACHE=m CONFIG_AMD_WBRF=y CONFIG_AMD_ISP_PLATFORM=m @@ -9598,18 +9758,7 @@ CONFIG_HP_WMI=m CONFIG_HP_BIOSCFG=m CONFIG_WIRELESS_HOTKEY=m CONFIG_IBM_RTL=m -CONFIG_IDEAPAD_LAPTOP=m -CONFIG_LENOVO_WMI_HOTKEY_UTILITIES=m -CONFIG_LENOVO_YMC=m CONFIG_SENSORS_HDAPS=m -CONFIG_THINKPAD_ACPI=m -CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y -# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set -# CONFIG_THINKPAD_ACPI_DEBUG is not set -# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set -CONFIG_THINKPAD_ACPI_VIDEO=y -CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y -CONFIG_THINKPAD_LMI=m CONFIG_INTEL_ATOMISP2_PDX86=y CONFIG_INTEL_ATOMISP2_LED=m CONFIG_INTEL_ATOMISP2_PM=m @@ -9621,6 +9770,7 @@ CONFIG_INTEL_PMC_SSRAM_TELEMETRY=m CONFIG_INTEL_PMT_CLASS=m CONFIG_INTEL_PMT_TELEMETRY=m CONFIG_INTEL_PMT_CRASHLOG=m +CONFIG_INTEL_PMT_DISCOVERY=m # # Intel Speed Select Technology interface support @@ -9660,6 +9810,25 @@ CONFIG_INTEL_TPMI=m CONFIG_INTEL_PLR_TPMI=m CONFIG_INTEL_TURBO_MAX_3=y CONFIG_INTEL_VSEC=m +CONFIG_IDEAPAD_LAPTOP=m +CONFIG_LENOVO_WMI_HOTKEY_UTILITIES=m +CONFIG_LENOVO_WMI_CAMERA=m +CONFIG_LENOVO_YMC=m +CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y +# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set +# CONFIG_THINKPAD_ACPI_DEBUG is not set +# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set +CONFIG_THINKPAD_ACPI_VIDEO=y +CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y +CONFIG_THINKPAD_LMI=m +CONFIG_YOGABOOK=m +CONFIG_YT2_1380=m +CONFIG_LENOVO_WMI_DATA01=m +CONFIG_LENOVO_WMI_EVENTS=m +CONFIG_LENOVO_WMI_HELPERS=m +CONFIG_LENOVO_WMI_GAMEZONE=m +CONFIG_LENOVO_WMI_TUNING=m CONFIG_ACPI_QUICKSTART=m CONFIG_MEEGOPAD_ANX7428=m CONFIG_MSI_EC=m @@ -9687,7 +9856,6 @@ CONFIG_TOPSTAR_LAPTOP=m CONFIG_SERIAL_MULTI_INSTANTIATE=m CONFIG_TOUCHSCREEN_DMI=y CONFIG_INSPUR_PLATFORM_PROFILE=m -CONFIG_LENOVO_WMI_CAMERA=m CONFIG_DASHARO_ACPI=m CONFIG_X86_ANDROID_TABLETS=m CONFIG_FW_ATTR_CLASS=m @@ -10011,7 +10179,9 @@ CONFIG_IIO_ADC_HELPER=m CONFIG_AD_SIGMA_DELTA=m CONFIG_AD4000=m CONFIG_AD4030=m +CONFIG_AD4080=m CONFIG_AD4130=m +CONFIG_AD4170_4=m CONFIG_AD4695=m CONFIG_AD4851=m CONFIG_AD7091R=m @@ -10027,6 +10197,7 @@ CONFIG_AD7291=m CONFIG_AD7292=m CONFIG_AD7298=m CONFIG_AD7380=m +CONFIG_AD7405=m CONFIG_AD7476=m CONFIG_AD7606=m CONFIG_AD7606_IFACE_PARALLEL=m @@ -10177,6 +10348,7 @@ CONFIG_VZ89X=m CONFIG_IIO_CROS_EC_SENSORS_CORE=m CONFIG_IIO_CROS_EC_SENSORS=m CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE=m +CONFIG_IIO_CROS_EC_ACTIVITY=m # # Hid Sensor IIO Common @@ -10593,6 +10765,7 @@ CONFIG_AS3935=m # Proximity and distance sensors # CONFIG_CROS_EC_MKBP_PROXIMITY=m +CONFIG_D3323AA=m CONFIG_HX9023S=m CONFIG_IRSD200=m CONFIG_ISL29501=m @@ -10673,6 +10846,7 @@ CONFIG_PWM_TWL_LED=m # # IRQ chip support # +CONFIG_IRQ_MSI_LIB=y CONFIG_MADERA_IRQ=m # end of IRQ chip support @@ -10740,7 +10914,6 @@ CONFIG_USB4=m CONFIG_ANDROID_BINDER_IPC=y CONFIG_ANDROID_BINDERFS=y CONFIG_ANDROID_BINDER_DEVICES="" -# CONFIG_ANDROID_BINDER_IPC_SELFTEST is not set # end of Android CONFIG_LIBNVDIMM=m @@ -10837,7 +11010,6 @@ CONFIG_MOST_CDEV=m CONFIG_MOST_SND=m # CONFIG_PECI is not set CONFIG_HTE=y -CONFIG_DPLL=y # end of Device Drivers # @@ -11021,6 +11193,7 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_TMPFS_XATTR=y CONFIG_TMPFS_INODE64=y CONFIG_TMPFS_QUOTA=y +CONFIG_ARCH_SUPPORTS_HUGETLBFS=y CONFIG_HUGETLBFS=y # CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set CONFIG_HUGETLB_PAGE=y @@ -11578,8 +11751,6 @@ CONFIG_CRYPTO_USER_API_AEAD=m # CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set # end of Userspace interface -CONFIG_CRYPTO_HASH_INFO=y - # # Accelerated Cryptographic Algorithms for CPU (x86) # @@ -11607,8 +11778,6 @@ CONFIG_CRYPTO_AEGIS128_AESNI_SSE2=m CONFIG_CRYPTO_NHPOLY1305_SSE2=m CONFIG_CRYPTO_NHPOLY1305_AVX2=m CONFIG_CRYPTO_POLYVAL_CLMUL_NI=m -CONFIG_CRYPTO_SHA1_SSSE3=m -CONFIG_CRYPTO_SHA512_SSSE3=m CONFIG_CRYPTO_SM3_AVX_X86_64=m CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m # end of Accelerated Cryptographic Algorithms for CPU (x86) @@ -11695,10 +11864,23 @@ CONFIG_GENERIC_IOMAP=y CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y CONFIG_ARCH_HAS_FAST_MULTIPLIER=y CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC7=m +CONFIG_CRC8=m +CONFIG_CRC16=y +CONFIG_CRC_CCITT=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC_T10DIF=y +CONFIG_CRC_T10DIF_ARCH=y +CONFIG_CRC32=y +CONFIG_CRC32_ARCH=y +CONFIG_CRC64=y +CONFIG_CRC64_ARCH=y +CONFIG_CRC_OPTIMIZATIONS=y # # Crypto library routines # +CONFIG_CRYPTO_HASH_INFO=y CONFIG_CRYPTO_LIB_UTILS=y CONFIG_CRYPTO_LIB_AES=y CONFIG_CRYPTO_LIB_AESCFB=y @@ -11721,32 +11903,17 @@ CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m CONFIG_CRYPTO_LIB_POLY1305=y CONFIG_CRYPTO_LIB_CHACHA20POLY1305=y CONFIG_CRYPTO_LIB_SHA1=y +CONFIG_CRYPTO_LIB_SHA1_ARCH=y CONFIG_CRYPTO_LIB_SHA256=y -CONFIG_CRYPTO_ARCH_HAVE_LIB_SHA256=y -CONFIG_CRYPTO_ARCH_HAVE_LIB_SHA256_SIMD=y -CONFIG_CRYPTO_LIB_SHA256_GENERIC=y +CONFIG_CRYPTO_LIB_SHA256_ARCH=y +CONFIG_CRYPTO_LIB_SHA512=y +CONFIG_CRYPTO_LIB_SHA512_ARCH=y CONFIG_CRYPTO_LIB_SM3=m CONFIG_CRYPTO_BLAKE2S_X86=y CONFIG_CRYPTO_CHACHA20_X86_64=y CONFIG_CRYPTO_POLY1305_X86_64=y -CONFIG_CRYPTO_SHA256_X86_64=y # end of Crypto library routines -CONFIG_CRC_CCITT=y -CONFIG_CRC16=y -CONFIG_CRC_T10DIF=y -CONFIG_ARCH_HAS_CRC_T10DIF=y -CONFIG_CRC_T10DIF_ARCH=y -CONFIG_CRC_ITU_T=m -CONFIG_CRC32=y -CONFIG_ARCH_HAS_CRC32=y -CONFIG_CRC32_ARCH=y -CONFIG_CRC64=y -CONFIG_ARCH_HAS_CRC64=y -CONFIG_CRC64_ARCH=y -CONFIG_CRC7=m -CONFIG_CRC8=m -CONFIG_CRC_OPTIMIZATIONS=y CONFIG_XXHASH=y # CONFIG_RANDOM32_SELFTEST is not set CONFIG_842_COMPRESS=m @@ -12121,7 +12288,6 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS=y CONFIG_HAVE_DYNAMIC_FTRACE_NO_PATCHABLE=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_SYSCALL_TRACEPOINTS=y CONFIG_HAVE_FENTRY=y CONFIG_HAVE_OBJTOOL_MCOUNT=y @@ -12138,6 +12304,7 @@ CONFIG_TRACING=y CONFIG_GENERIC_TRACER=y CONFIG_TRACING_SUPPORT=y CONFIG_FTRACE=y +# CONFIG_TRACEFS_AUTOMOUNT_DEPRECATED is not set CONFIG_BOOTTIME_TRACING=y CONFIG_FUNCTION_TRACER=y CONFIG_FUNCTION_GRAPH_TRACER=y @@ -12169,11 +12336,11 @@ CONFIG_PROBE_EVENTS_BTF_ARGS=y CONFIG_KPROBE_EVENTS=y # CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set CONFIG_UPROBE_EVENTS=y +CONFIG_EPROBE_EVENTS=y CONFIG_BPF_EVENTS=y CONFIG_DYNAMIC_EVENTS=y CONFIG_PROBE_EVENTS=y CONFIG_BPF_KPROBE_OVERRIDE=y -CONFIG_FTRACE_MCOUNT_RECORD=y CONFIG_FTRACE_MCOUNT_USE_CC=y CONFIG_TRACING_MAP=y CONFIG_SYNTH_EVENTS=y @@ -12281,6 +12448,7 @@ CONFIG_ASYNC_RAID6_TEST=m # CONFIG_TEST_FPU is not set # CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set # CONFIG_TEST_OBJPOOL is not set +# CONFIG_TEST_KEXEC_HANDOVER is not set CONFIG_ARCH_USE_MEMTEST=y CONFIG_MEMTEST=y # CONFIG_HYPERV_TESTING is not set diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index 8457ab0584..572581b67e 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.16.config \ No newline at end of file +../../../configs/surface-6.17.config \ No newline at end of file From f85c048e0a6a92ab8bd017b6adc72911c31ed795 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 11 Oct 2025 04:24:18 +0200 Subject: [PATCH 131/236] Update Fedora kernels to v6.16.11 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index b4a197df1b..d2667535c4 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.16.9-0" +PACKAGE_TAG = "kernel-6.16.11-0" ## ## The release number of the modified kernel package. From 1548fe880d3d1b7849c49df4c03309850ed8c427 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 11 Oct 2025 04:33:49 +0200 Subject: [PATCH 132/236] Update Debian kernel to v6.17.1 --- ...secureboot-pre-signing-to-the-kernel.patch | 2 +- ...-integrity-Only-use-machine-keyring-.patch | 2 +- ...sallow-unprivileged-CLONE_NEWUSER-by.patch | 20 +++++++++---------- ...uild-Copy-config-to-target-directory.patch | 2 +- ...001-kbuild-Link-sign-file-statically.patch | 2 +- pkg/debian/kernel/version.conf | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch index 1feb343468..92065d0d6c 100644 --- a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch +++ b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch @@ -1,4 +1,4 @@ -From 68aa2761f6a59f4e826c2a66b8d2cf4d26053ce0 Mon Sep 17 00:00:00 2001 +From 011c8c949f039a5b634fd2070b4dd8d8600716ea Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 22 Sep 2019 22:44:16 +0200 Subject: [PATCH] Add secureboot pre-signing to the kernel diff --git a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch index a7b02b31ff..961aa8e326 100644 --- a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch +++ b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch @@ -1,4 +1,4 @@ -From 671aba7365d3ab2c900951b959c39ce6890e0080 Mon Sep 17 00:00:00 2001 +From c422df6afed4ed5337cc96588f52c628840a4ed6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 22:54:05 +0100 Subject: [PATCH] Partially revert "integrity: Only use machine keyring when diff --git a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch index fde2152559..91dcf165bd 100644 --- a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch +++ b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch @@ -1,4 +1,4 @@ -From eaad52af3805d3bd81d56e5325054d0efc37f875 Mon Sep 17 00:00:00 2001 +From ba645e31140ff6ecd6a8b28f8d72cb5132f60625 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Fri, 31 May 2013 19:12:12 +0100 Subject: [PATCH] add sysctl to disallow unprivileged CLONE_NEWUSER by default @@ -20,10 +20,10 @@ Signed-off-by: Serge Hallyn 3 files changed, 32 insertions(+) diff --git a/kernel/fork.c b/kernel/fork.c -index 1ee8eb11f38b..59d8c7ba6c54 100644 +index 6ca8689a83b5..483c28b98e5a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c -@@ -122,6 +122,12 @@ +@@ -123,6 +123,12 @@ #include @@ -36,7 +36,7 @@ index 1ee8eb11f38b..59d8c7ba6c54 100644 /* * Minimum number of threads to boot the kernel */ -@@ -1933,6 +1939,10 @@ __latent_entropy struct task_struct *copy_process( +@@ -1938,6 +1944,10 @@ __latent_entropy struct task_struct *copy_process( if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -47,7 +47,7 @@ index 1ee8eb11f38b..59d8c7ba6c54 100644 /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. -@@ -3099,6 +3109,12 @@ int ksys_unshare(unsigned long unshare_flags) +@@ -3105,6 +3115,12 @@ int ksys_unshare(unsigned long unshare_flags) if (unshare_flags & CLONE_NEWNS) unshare_flags |= CLONE_FS; @@ -61,10 +61,10 @@ index 1ee8eb11f38b..59d8c7ba6c54 100644 if (err) goto bad_unshare_out; diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 9b4f0cff76ea..c388b1aa4d3d 100644 +index cb6196e3fa99..c955e49a4b7a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c -@@ -77,6 +77,10 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals); +@@ -36,6 +36,10 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals); static const int ngroups_max = NGROUPS_MAX; static const int cap_last_cap = CAP_LAST_CAP; @@ -75,10 +75,10 @@ index 9b4f0cff76ea..c388b1aa4d3d 100644 #ifdef CONFIG_PROC_SYSCTL /** -@@ -1581,6 +1585,15 @@ int proc_do_static_key(const struct ctl_table *table, int write, +@@ -1455,6 +1459,15 @@ int proc_do_static_key(const struct ctl_table *table, int write, } - static const struct ctl_table kern_table[] = { + static const struct ctl_table sysctl_subsys_table[] = { +#ifdef CONFIG_USER_NS + { + .procname = "unprivileged_userns_clone", @@ -90,7 +90,7 @@ index 9b4f0cff76ea..c388b1aa4d3d 100644 +#endif #ifdef CONFIG_PROC_SYSCTL { - .procname = "tainted", + .procname = "sysctl_writes_strict", diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 682f40d5632d..bf265ad528f9 100644 --- a/kernel/user_namespace.c diff --git a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch index 79e268aee1..38b940582f 100644 --- a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch +++ b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch @@ -1,4 +1,4 @@ -From a85832b815c784d29d2287e22143bf3c0accf4b8 Mon Sep 17 00:00:00 2001 +From 62bc6c700904071cd13e3baa8117e94f7e6a571d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 03:02:20 +0200 Subject: [PATCH] kbuild: Copy config to target directory diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index 8875eac129..4f8ab6a299 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -1,4 +1,4 @@ -From 56d102e8604b6f22008583a51ccbc7477817231d Mon Sep 17 00:00:00 2001 +From c6be12fd8b6b036ca919511cd947c5d18cf03844 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:10:28 +0200 Subject: [PATCH] kbuild: Link sign-file statically diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 5f13c4dbdf..d0d563bc7f 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.16.9" +KERNEL_VERSION="6.17.1" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From d618e1ea01ef1e8aa3814ecb9ccd06fcc6b99631 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 11 Oct 2025 05:07:10 +0200 Subject: [PATCH 133/236] pkg/debian: Use Ubuntu 22.04 as new build base --- .github/workflows/debian.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 086de5c412..92e703c94c 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -30,7 +30,7 @@ jobs: - name: Initialize containers run: | bash ./.github/scripts/container/create.sh \ - ubuntu:20.04 + ubuntu:22.04 - name: Install build dependencies run: | From 6a2561a2f94065586468feafd35c13174f6b08ab Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 11 Oct 2025 06:01:57 +0200 Subject: [PATCH 134/236] pkg/debian: Add rust dependencies --- .github/scripts/package/debian.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/scripts/package/debian.sh b/.github/scripts/package/debian.sh index 1acc652f30..9548345764 100644 --- a/.github/scripts/package/debian.sh +++ b/.github/scripts/package/debian.sh @@ -20,6 +20,8 @@ MAINLINE_BRANCH="cod/mainline" case "${1:-}" in setup-builddeps) + export PATH="$HOME/.cargo/bin:$PATH" + SOURCES="$(sed 's/^deb /deb-src /' /etc/apt/sources.list)" echo "${SOURCES}" >> /etc/apt/sources.list @@ -29,7 +31,8 @@ setup-builddeps) apt-get update apt-get upgrade apt-get install build-essential fakeroot rsync git wget software-properties-common \ - zstd lz4 sbsigntool debhelper dpkg-dev dpkg-sig pkg-config + zstd lz4 sbsigntool debhelper dpkg-dev dpkg-sig pkg-config \ + llvm-15 clang-15 libclang-15-dev apt-get build-dep linux # install python 3.11, required for configuring the kernel via Ubuntu's annotation format @@ -43,6 +46,11 @@ setup-builddeps) rm -f /usr/bin/python3 ln -s /usr/bin/python3.11 /usr/bin/python ln -s /usr/bin/python3.11 /usr/bin/python3 + + # install rust dependencies (required for now because of minimum version requirements) + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + rustup component add rust-src rustfmt clippy + cargo install --locked bindgen-cli ;; setup-secureboot) if [ -z "${SB_KEY:-}" ]; then @@ -57,6 +65,8 @@ setup-secureboot) cp pkg/keys/surface.crt pkg/debian/kernel/keys/MOK.crt ;; build-packages) + export PATH="$HOME/.cargo/bin:$PATH" + pushd pkg/debian/kernel || exit 1 . version.conf @@ -110,6 +120,9 @@ build-packages) # Set kernel localversion export LOCALVERSION="${KERNEL_LOCALVERSION}-${KERNEL_REVISION}" + # Get debug info for rust + make rustavailable + make bindeb-pkg -j "$(nproc)" popd || exit 1 From 619cde91c2439a1084a318df02d5ec97d17981fa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 11 Oct 2025 06:03:02 +0200 Subject: [PATCH 135/236] pkg/debian: Bump release version --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index d0d563bc7f..309a4f492c 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ KERNEL_VERSION="6.17.1" -KERNEL_REVISION="1" +KERNEL_REVISION="2" KERNEL_LOCALVERSION="-surface" From 50d0ed6be462a5fdb643cfe8469bf69158afae42 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 11 Oct 2025 06:59:02 +0200 Subject: [PATCH 136/236] pkg/arch: Drop BPF stuff --- pkg/arch/kernel/PKGBUILD | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 618101c0ab..11405fc4e1 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -132,7 +132,6 @@ prepare() { build() { cd $_srcname _make all - _make -C tools/bpf/bpftool vmlinux.h feature-clang-bpf-co-re=1 } _package() { @@ -195,7 +194,7 @@ _package-headers() { echo "Installing build files..." install -Dt "$builddir" -m644 .config Makefile Module.symvers System.map \ - localversion.* version vmlinux tools/bpf/bpftool/vmlinux.h + localversion.* version vmlinux install -Dt "$builddir/kernel" -m644 kernel/Makefile install -Dt "$builddir/arch/x86" -m644 arch/x86/Makefile cp -t "$builddir" -a scripts @@ -204,9 +203,6 @@ _package-headers() { # required when STACK_VALIDATION is enabled install -Dt "$builddir/tools/objtool" tools/objtool/objtool - # required when DEBUG_INFO_BTF_MODULES is enabled - install -Dt "$builddir/tools/bpf/resolve_btfids" tools/bpf/resolve_btfids/resolve_btfids - echo "Installing headers..." cp -t "$builddir" -a include cp -t "$builddir/arch/x86" -a arch/x86/include From 273076264413c6ff078a928789d52a79691204e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 20:38:17 +0100 Subject: [PATCH 137/236] Add patch to filter BTN_0 (FN key) events on Surface devices Fixes #1851 - FN key causing focus to get stuck in KWin Wayland The Surface Aggregator Module firmware incorrectly reports the FN key as BTN_0 (button 256). This can get stuck in pressed state, flooding the input system and breaking focus tracking in compositors. This patch adds a new HID driver (hid-surface.c) that filters BTN_0 events while allowing all other keyboard/touchpad functionality to work normally. Tested on Surface Laptop 4 AMD with KDE Plasma Wayland. --- patches/6.16/0016-hid-surface-fn-key.patch | 157 +++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 patches/6.16/0016-hid-surface-fn-key.patch diff --git a/patches/6.16/0016-hid-surface-fn-key.patch b/patches/6.16/0016-hid-surface-fn-key.patch new file mode 100644 index 0000000000..fb9cbb61ac --- /dev/null +++ b/patches/6.16/0016-hid-surface-fn-key.patch @@ -0,0 +1,157 @@ +From 8ec2ee811c7d8c373f0a012f09f8f1582a6c3cdb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= +Date: Fri, 10 Oct 2025 19:04:03 +0100 +Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) + +The Surface Aggregator Module firmware incorrectly reports the FN key +as BTN_0 (button 256) through runtime HID events. This button can get +stuck in pressed state, flooding the input system and breaking focus +tracking in KWin Wayland compositor. + +Add a new hid-surface driver that filters BTN_0 events using the event +callback. The FN key should be handled as a hardware modifier and not +reported to the OS. + +Tested on Surface Laptop 4 AMD with KDE Plasma Wayland. After the fix: +- FN key combinations work correctly (volume, brightness) +- Focus tracking no longer breaks +- Mouse clicks work on all windows + +Fixes: https://github.com/linux-surface/linux-surface/issues/1851 +--- + drivers/hid/Kconfig | 8 ++++ + drivers/hid/Makefile | 1 + + drivers/hid/hid-surface.c | 90 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 99 insertions(+) + create mode 100644 drivers/hid/hid-surface.c + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index d6bc87be4854..ebb29cd695fe 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1131,6 +1131,14 @@ config HID_SUNPLUS + help + Support for Sunplus wireless desktop. + ++config HID_SURFACE ++ tristate "Microsoft Surface" ++ depends on SURFACE_AGGREGATOR ++ help ++ Say Y here to enable HID driver for Microsoft Surface integrated ++ keyboard and touchpad. This driver filters out erroneous BTN_0 ++ (FN key) events that can cause input focus issues. ++ + config HID_RMI + tristate "Synaptics RMI4 device support" + select RMI4_CORE +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index d939da7ac2e8..db4e80893ce5 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,6 +173,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++obj-$(CONFIG_HID_SURFACE) += hid-surface.o + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + +diff --git a/drivers/hid/hid-surface.c b/drivers/hid/hid-surface.c +new file mode 100644 +index 000000000000..a171ea65672f +--- /dev/null ++++ b/drivers/hid/hid-surface.c +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * HID driver for Microsoft Surface devices ++ * ++ * Copyright (c) 2025 Linux Surface Project ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++/* ++ * The Surface Aggregator Module firmware incorrectly reports the FN key ++ * as BTN_0 (button 256). This button can get stuck in pressed state, ++ * flooding the input system and breaking focus tracking in some ++ * compositors. Filter out BTN_0 as FN should be handled as a hardware ++ * modifier, not reported to the OS. ++ */ ++static int surface_input_mapping(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ /* ++ * Filter BTN_0 during input mapping in case it appears in the ++ * HID descriptor (defense in depth). ++ */ ++ if (usage->type == EV_KEY && usage->code == BTN_0) ++ return -1; /* Don't map this usage */ ++ ++ return 0; /* Use default mapping */ ++} ++ ++static int surface_event(struct hid_device *hdev, struct hid_field *field, ++ struct hid_usage *usage, __s32 value) ++{ ++ /* ++ * The Surface Aggregator Module firmware reports the FN key as BTN_0 ++ * at runtime. This button can get stuck in pressed state, flooding ++ * the input system and breaking focus tracking. Filter out these ++ * events as FN should be a hardware modifier, not reported to the OS. ++ */ ++ if (usage->type == EV_KEY && usage->code == BTN_0) ++ return 1; /* Event handled, don't process further */ ++ ++ return 0; /* Process event normally */ ++} ++ ++static int surface_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ int ret; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "parse failed\n"); ++ return ret; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ++ if (ret) { ++ hid_err(hdev, "hw start failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct hid_device_id surface_devices[] = { ++ { HID_DEVICE(BUS_HOST, HID_GROUP_GENERIC, ++ USB_VENDOR_ID_MICROSOFT, 0x09AE) }, /* Surface Keyboard */ ++ { HID_DEVICE(BUS_HOST, HID_GROUP_GENERIC, ++ USB_VENDOR_ID_MICROSOFT, 0x09AF) }, /* Surface Mouse/Touchpad */ ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, surface_devices); ++ ++static struct hid_driver surface_driver = { ++ .name = "surface", ++ .id_table = surface_devices, ++ .probe = surface_probe, ++ .input_mapping = surface_input_mapping, ++ .event = surface_event, ++}; ++module_hid_driver(surface_driver); ++ ++MODULE_AUTHOR("Linux Surface Project"); ++MODULE_DESCRIPTION("Microsoft Surface HID driver"); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + From 4938d50e1fe48a256d5bf788983da76294cde519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Sun, 12 Oct 2025 15:38:54 +0100 Subject: [PATCH 138/236] Add patch for kernel 6.17 as well The fix also applies to kernel 6.17.1 - tested and confirmed bug exists there too. --- patches/6.17/0016-hid-surface-fn-key.patch | 157 +++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 patches/6.17/0016-hid-surface-fn-key.patch diff --git a/patches/6.17/0016-hid-surface-fn-key.patch b/patches/6.17/0016-hid-surface-fn-key.patch new file mode 100644 index 0000000000..fb9cbb61ac --- /dev/null +++ b/patches/6.17/0016-hid-surface-fn-key.patch @@ -0,0 +1,157 @@ +From 8ec2ee811c7d8c373f0a012f09f8f1582a6c3cdb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= +Date: Fri, 10 Oct 2025 19:04:03 +0100 +Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) + +The Surface Aggregator Module firmware incorrectly reports the FN key +as BTN_0 (button 256) through runtime HID events. This button can get +stuck in pressed state, flooding the input system and breaking focus +tracking in KWin Wayland compositor. + +Add a new hid-surface driver that filters BTN_0 events using the event +callback. The FN key should be handled as a hardware modifier and not +reported to the OS. + +Tested on Surface Laptop 4 AMD with KDE Plasma Wayland. After the fix: +- FN key combinations work correctly (volume, brightness) +- Focus tracking no longer breaks +- Mouse clicks work on all windows + +Fixes: https://github.com/linux-surface/linux-surface/issues/1851 +--- + drivers/hid/Kconfig | 8 ++++ + drivers/hid/Makefile | 1 + + drivers/hid/hid-surface.c | 90 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 99 insertions(+) + create mode 100644 drivers/hid/hid-surface.c + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index d6bc87be4854..ebb29cd695fe 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1131,6 +1131,14 @@ config HID_SUNPLUS + help + Support for Sunplus wireless desktop. + ++config HID_SURFACE ++ tristate "Microsoft Surface" ++ depends on SURFACE_AGGREGATOR ++ help ++ Say Y here to enable HID driver for Microsoft Surface integrated ++ keyboard and touchpad. This driver filters out erroneous BTN_0 ++ (FN key) events that can cause input focus issues. ++ + config HID_RMI + tristate "Synaptics RMI4 device support" + select RMI4_CORE +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index d939da7ac2e8..db4e80893ce5 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -173,6 +173,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++obj-$(CONFIG_HID_SURFACE) += hid-surface.o + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + +diff --git a/drivers/hid/hid-surface.c b/drivers/hid/hid-surface.c +new file mode 100644 +index 000000000000..a171ea65672f +--- /dev/null ++++ b/drivers/hid/hid-surface.c +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * HID driver for Microsoft Surface devices ++ * ++ * Copyright (c) 2025 Linux Surface Project ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++/* ++ * The Surface Aggregator Module firmware incorrectly reports the FN key ++ * as BTN_0 (button 256). This button can get stuck in pressed state, ++ * flooding the input system and breaking focus tracking in some ++ * compositors. Filter out BTN_0 as FN should be handled as a hardware ++ * modifier, not reported to the OS. ++ */ ++static int surface_input_mapping(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ /* ++ * Filter BTN_0 during input mapping in case it appears in the ++ * HID descriptor (defense in depth). ++ */ ++ if (usage->type == EV_KEY && usage->code == BTN_0) ++ return -1; /* Don't map this usage */ ++ ++ return 0; /* Use default mapping */ ++} ++ ++static int surface_event(struct hid_device *hdev, struct hid_field *field, ++ struct hid_usage *usage, __s32 value) ++{ ++ /* ++ * The Surface Aggregator Module firmware reports the FN key as BTN_0 ++ * at runtime. This button can get stuck in pressed state, flooding ++ * the input system and breaking focus tracking. Filter out these ++ * events as FN should be a hardware modifier, not reported to the OS. ++ */ ++ if (usage->type == EV_KEY && usage->code == BTN_0) ++ return 1; /* Event handled, don't process further */ ++ ++ return 0; /* Process event normally */ ++} ++ ++static int surface_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ int ret; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "parse failed\n"); ++ return ret; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ++ if (ret) { ++ hid_err(hdev, "hw start failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct hid_device_id surface_devices[] = { ++ { HID_DEVICE(BUS_HOST, HID_GROUP_GENERIC, ++ USB_VENDOR_ID_MICROSOFT, 0x09AE) }, /* Surface Keyboard */ ++ { HID_DEVICE(BUS_HOST, HID_GROUP_GENERIC, ++ USB_VENDOR_ID_MICROSOFT, 0x09AF) }, /* Surface Mouse/Touchpad */ ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, surface_devices); ++ ++static struct hid_driver surface_driver = { ++ .name = "surface", ++ .id_table = surface_devices, ++ .probe = surface_probe, ++ .input_mapping = surface_input_mapping, ++ .event = surface_event, ++}; ++module_hid_driver(surface_driver); ++ ++MODULE_AUTHOR("Linux Surface Project"); ++MODULE_DESCRIPTION("Microsoft Surface HID driver"); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + From 9751d402acfa0d0f0042291f15a02a1567c6db66 Mon Sep 17 00:00:00 2001 From: Gerardo Mora Date: Thu, 30 Oct 2025 21:25:23 -0600 Subject: [PATCH 139/236] pkg/fedora: adding support for fedora 43 --- .github/workflows/fedora-43.yml | 125 ++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 .github/workflows/fedora-43.yml diff --git a/.github/workflows/fedora-43.yml b/.github/workflows/fedora-43.yml new file mode 100644 index 0000000000..70061087c5 --- /dev/null +++ b/.github/workflows/fedora-43.yml @@ -0,0 +1,125 @@ +name: Fedora 43 + +env: + FEDORA: 43 + GPG_KEY_ID: 56C464BAAC421453 + +on: + push: + tags: + - 'fedora-43-*' + + repository_dispatch: + workflow_dispatch: + +jobs: + build: + name: Build Kernel + runs-on: ubuntu-latest + steps: + - name: Maximize disk space + uses: easimon/maximize-build-space@master + with: + root-reserve-mb: 5120 + remove-dotnet: true + remove-android: true + remove-docker-images: true + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Initialize containers + run: | + bash ./.github/scripts/container/create.sh \ + registry.fedoraproject.org/fedora:${{ env.FEDORA }} + + - name: Install build dependencies + run: | + bash ./.github/scripts/container/exec.sh \ + -- \ + bash ./.github/scripts/package/fedora.sh setup-builddeps + + - name: Setup secureboot certificate + env: + SB_KEY: ${{ secrets.SURFACE_SB_KEY }} + run: | + bash ./.github/scripts/container/exec.sh \ + -e SB_KEY \ + -- \ + bash ./.github/scripts/package/fedora.sh setup-secureboot + + - name: Build packages + run: | + bash ./.github/scripts/container/exec.sh \ + -- \ + bash ./.github/scripts/package/fedora.sh build-packages + + - name: Sign packages + env: + GPG_KEY: ${{ secrets.LINUX_SURFACE_GPG_KEY }} + run: | + bash ./.github/scripts/container/exec.sh \ + -e GPG_KEY \ + -e GPG_KEY_ID \ + -- \ + bash ./.github/scripts/package/fedora.sh sign-packages + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: fedora-${{ env.FEDORA }}-latest + path: pkg/fedora/kernel-surface/out/x86_64 + + release: + name: Publish release + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/') + needs: [build] + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: fedora-${{ env.FEDORA }}-latest + path: fedora-${{ env.FEDORA }}-latest + + - name: Upload assets + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + file: ./*-latest/* + tag: ${{ github.ref }} + overwrite: true + file_glob: true + + repo: + name: Update package repository + needs: [release] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: fedora-${{ env.FEDORA }}-latest + path: fedora-${{ env.FEDORA }}-latest + + - name: Initialize containers + run: | + bash ./.github/scripts/container/create.sh \ + registry.fedoraproject.org/fedora:${{ env.FEDORA }} + + - name: Update repository + env: + SURFACEBOT_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + GIT_REF: ${{ github.ref }} + BRANCH_STAGING: u/staging + run: | + bash ./.github/scripts/container/exec.sh \ + -e SURFACEBOT_TOKEN \ + -e GIT_REF \ + -e BRANCH_STAGING \ + -e GITHUB_REPOSITORY \ + -- \ + bash ./.github/scripts/repository/fedora.sh ${{ env.FEDORA }} From 6256021c3dbc9eaca75ed325a6111f872fd549b4 Mon Sep 17 00:00:00 2001 From: tmarkov Date: Fri, 14 Nov 2025 21:36:33 +0200 Subject: [PATCH 140/236] update cameras patch --- patches/6.12/0012-cameras.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index 64014fd030..e076e492cb 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -247,7 +247,7 @@ index 3de463c3d13b..0a012eeed30a 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - const char *func, u32 polarity) + const char *func, unsigned long gpio_flags) { int ret; + const struct acpi_device_id ov7251_ids[] = { @@ -268,7 +268,7 @@ index 3de463c3d13b..0a012eeed30a 100644 + */ + if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { + func = "enable"; -+ polarity ^= GPIO_ACTIVE_LOW; ++ gpio_flags ^= GPIO_ACTIVE_LOW; + } + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], From 3cda2c6cbe8adecab9159c6194d9f7e9f84f0e49 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Dec 2025 21:45:46 +0100 Subject: [PATCH 141/236] Update v6.12 patches Changes: - Rebase onto v6.12.63 --- patches/6.12/0001-secureboot.patch | 20 +++--- patches/6.12/0002-surface3-oemb.patch | 4 +- patches/6.12/0003-mwifiex.patch | 24 +++---- patches/6.12/0004-ath10k.patch | 16 ++--- patches/6.12/0005-ipts.patch | 34 ++++----- patches/6.12/0006-ithc.patch | 18 ++--- patches/6.12/0007-surface-sam-over-hid.patch | 14 ++-- patches/6.12/0008-surface-button.patch | 8 +-- patches/6.12/0009-surface-typecover.patch | 50 +++++++------- patches/6.12/0010-surface-shutdown.patch | 16 ++--- patches/6.12/0011-surface-gpe.patch | 4 +- patches/6.12/0012-cameras.patch | 72 ++++++++++---------- patches/6.12/0013-amd-gpio.patch | 22 +++--- patches/6.12/0014-rtc.patch | 16 ++--- 14 files changed, 159 insertions(+), 159 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index addb86e813..be2700f1b7 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From bbcfb18eb05bd92e4501ca35bdfd558c849ddeda Mon Sep 17 00:00:00 2001 +From 01edde8580dac0f700507ca50c66ef77881e4d2d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.47.1 +2.51.0 -From 9a796344897d077f1fc977ab026315c2cfcd3960 Mon Sep 17 00:00:00 2001 +From 1498ad5095e16250353ba89021d731afa695fb2f Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,10 +53,10 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index d401577b5a6a..5a812e0b740a 100644 +index e88505e945d5..15961654b652 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3066,6 +3066,11 @@ +@@ -3085,6 +3085,11 @@ to extract confidential information from the kernel are also disabled. @@ -69,7 +69,7 @@ index d401577b5a6a..5a812e0b740a 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index e35829d36039..6d54eb03b63d 100644 +index 85008ead2ac9..48df5cfafde6 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -37,6 +37,7 @@ @@ -80,7 +80,7 @@ index e35829d36039..6d54eb03b63d 100644 static int nocompress; static int noresume; static int nohibernate; -@@ -92,7 +93,7 @@ void hibernate_release(void) +@@ -97,7 +98,7 @@ bool hibernation_in_progress(void) bool hibernation_available(void) { return nohibernate == 0 && @@ -89,7 +89,7 @@ index e35829d36039..6d54eb03b63d 100644 !secretmem_active() && !cxl_mem_active(); } -@@ -1426,6 +1427,12 @@ static int __init nohibernate_setup(char *str) +@@ -1436,6 +1437,12 @@ static int __init nohibernate_setup(char *str) return 1; } @@ -102,11 +102,11 @@ index e35829d36039..6d54eb03b63d 100644 static const char * const comp_alg_enabled[] = { #if IS_ENABLED(CONFIG_CRYPTO_LZO) COMPRESSION_ALGO_LZO, -@@ -1484,3 +1491,4 @@ __setup("hibernate=", hibernate_setup); +@@ -1494,3 +1501,4 @@ __setup("hibernate=", hibernate_setup); __setup("resumewait", resumewait_setup); __setup("resumedelay=", resumedelay_setup); __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index ab40dd606c..827d67f433 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 2ce5cf2a597c9015c64ea9f386a396f97b8589c6 Mon Sep 17 00:00:00 2001 +From 725efa527cfc7d487fa30b61d80c2b9a52c4edb7 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,5 +97,5 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index 523a943588..78ced1a910 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From ed54461506b98c1bc8ae8dc5f7385de1f900ed0b Mon Sep 17 00:00:00 2001 +From 1f0efbe2eb539540b68018722c4f85afc14bda95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.47.1 +2.51.0 -From a93a869673e056cf2a2c46b9438edaca8f5e2645 Mon Sep 17 00:00:00 2001 +From dabaf45293d28679d9f6d41bd99788d78f1cb24f Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.47.1 +2.51.0 -From bcc616a02ed2a9e059d2e7a1dd5b5289412efcbb Mon Sep 17 00:00:00 2001 +From f490bcbca816c939c3aa149b11c26081e3387fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,18 +356,18 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 11755cb1eb16..e69c6c9957a2 100644 +index dc0c45756c44..cba0110b17e3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c -@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; - #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) +@@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) #define BTUSB_ACTIONS_SEMI BIT(27) -+#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + #define BTUSB_BARROT BIT(28) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(29) static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ -@@ -432,6 +433,7 @@ static const struct usb_device_id quirks_table[] = { +@@ -469,6 +470,7 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, @@ -375,7 +375,7 @@ index 11755cb1eb16..e69c6c9957a2 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3837,6 +3839,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -3995,6 +3997,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 11755cb1eb16..e69c6c9957a2 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index e1e6253a8b..bd5e401e5d 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From cc9a74a369def421de56b0581f6131c4cd15355d Mon Sep 17 00:00:00 2001 +From 71c1ca84a24c0817454d783a3a184b091d19b291 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,10 +20,10 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index b3294287bce1..2936fdae823c 100644 +index f9b51d98d20b..e04bac901c60 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -40,6 +40,9 @@ static bool fw_diag_log; +@@ -41,6 +41,9 @@ static bool fw_diag_log; /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; @@ -33,7 +33,7 @@ index b3294287bce1..2936fdae823c 100644 unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); -@@ -52,6 +55,9 @@ module_param(fw_diag_log, bool, 0644); +@@ -53,6 +56,9 @@ module_param(fw_diag_log, bool, 0644); module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); @@ -43,7 +43,7 @@ index b3294287bce1..2936fdae823c 100644 MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); -@@ -61,6 +67,9 @@ MODULE_PARM_DESC(frame_mode, +@@ -62,6 +68,9 @@ MODULE_PARM_DESC(frame_mode, MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); @@ -53,7 +53,7 @@ index b3294287bce1..2936fdae823c 100644 static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA988X_HW_2_0_VERSION, -@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) +@@ -932,6 +941,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) return 0; } @@ -96,7 +96,7 @@ index b3294287bce1..2936fdae823c 100644 static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, const char *dir, const char *file) -@@ -945,6 +990,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, +@@ -946,6 +991,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, if (dir == NULL) dir = "."; @@ -116,5 +116,5 @@ index b3294287bce1..2936fdae823c 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index 0e4a8c8176..938ecad68d 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From 3e89507b8f6c6d36e5bf587a74c65be5d9796ffd Mon Sep 17 00:00:00 2001 +From e3f8caa6000b3a6ba9eca18475e99a69afdbe2f2 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index c3a6657dcd4a..82eef2f4eb0a 100644 +index a4f75dc36929..e4a561b257d7 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index c3a6657dcd4a..82eef2f4eb0a 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 6589635f8ba3..a1df48a434e2 100644 +index bc0fc584a8e4..51a91ef66cda 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.47.1 +2.51.0 -From 1d6df5a556693e735cc78a603c29112a76ee883b Mon Sep 17 00:00:00 2001 +From 75645d9a045f577b0bbe78444d589bb2d04f1564 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index cc23cfcdeb2d..c010aebe6cc1 100644 +index c799cc67db34..65adfc813ee6 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -40,6 +40,11 @@ @@ -91,7 +91,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -2046,6 +2053,9 @@ static int device_def_domain_type(struct device *dev) +@@ -2066,6 +2073,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 } return 0; -@@ -2344,6 +2354,9 @@ static int __init init_dmars(void) +@@ -2364,6 +2374,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 check_tylersburg_isoch(); /* -@@ -4651,6 +4664,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4691,6 +4704,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4686,6 +4711,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4729,6 +4754,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index cc23cfcdeb2d..c010aebe6cc1 100644 { if (risky_device(dev)) -- -2.47.1 +2.51.0 -From e4e616d49f7a021b83cd0114f0642090e88a054f Mon Sep 17 00:00:00 2001 +From 659fcb72a471a0ab78123458fcf78a27183a8688 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,10 +211,10 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index f8a56d631242..38eb29e4cc31 100644 +index 95a4ede27099..777d4619d06d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1373,4 +1373,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" +@@ -1388,4 +1388,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" source "drivers/hid/surface-hid/Kconfig" @@ -222,10 +222,10 @@ index f8a56d631242..38eb29e4cc31 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 496dab54c73a..02588e5d01eb 100644 +index 27ee02bf6f26..15a67dc834a6 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -170,3 +170,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ +@@ -170,3 +170,5 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ @@ -3237,5 +3237,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index ecc37aa866..1205849c44 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From d07e07e448b9b1ac7102911263626b623f138a28 Mon Sep 17 00:00:00 2001 +From e2445c4f69af8d6ea2de2754a6ff084b861ad76d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,10 +10,10 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 7a6d188e3bea..0179baee4596 100644 +index 71b3383b7115..8409824b5157 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c -@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) +@@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) data.busmatch_count = 0; pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); @@ -37,9 +37,9 @@ index 7a6d188e3bea..0179baee4596 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.47.1 +2.51.0 -From 280c63dff160b59d1cbac71a63dc7f16d335fec9 Mon Sep 17 00:00:00 2001 +From a2f09b7f8cce1475141c71586bacc46120146278 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,10 +86,10 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 38eb29e4cc31..76ad7d9143c7 100644 +index 777d4619d06d..d23316df4f5d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1375,4 +1375,6 @@ source "drivers/hid/surface-hid/Kconfig" +@@ -1390,4 +1390,6 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/ipts/Kconfig" @@ -97,7 +97,7 @@ index 38eb29e4cc31..76ad7d9143c7 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 02588e5d01eb..1ea3d2e0d4e9 100644 +index 15a67dc834a6..fcbc18ceb521 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -2767,5 +2767,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index a65acd8e4f..298d95609d 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 064893f3e33bd77cecece7ea4047b3a6e1147fe2 Mon Sep 17 00:00:00 2001 +From bed92ec0444735aad7ce2cb42b791c637acaad0b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,10 +55,10 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index 14ae0cfc325e..6197c5252d2a 100644 +index f43067f6797e..1761ca30e17a 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c -@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, +@@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, return (ret == 1) ? 0 : -EIO; } @@ -86,7 +86,7 @@ index 14ae0cfc325e..6197c5252d2a 100644 static acpi_status i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, -@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, +@@ -763,6 +784,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, } break; @@ -107,9 +107,9 @@ index 14ae0cfc325e..6197c5252d2a 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.47.1 +2.51.0 -From f6714cb9a95aeec3379336df70e7cc8d9537f727 Mon Sep 17 00:00:00 2001 +From b9beaed33aca9e6d35802a13fec298bd88654aec Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index 934e9156d2..a7231ab92f 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From 9d06bf6cc92b13c9e4c4781484b82804c4150d80 Mon Sep 17 00:00:00 2001 +From 3161aa7937ea6cf7bc57fec961e74bdd86c2fc6d Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index 5c5d407fe965..4e1bfe90e730 100644 /* -- -2.47.1 +2.51.0 -From f870bb021693abb7ea617c323216c615151b62e1 Mon Sep 17 00:00:00 2001 +From b693acb105f441cae83c53eeffa5f81aa5e80ec9 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index de3cb8160d..2396cf8cdc 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From df8f9981df6f0a92100266397ded155314efc7e3 Mon Sep 17 00:00:00 2001 +From 9acb0bf01bdc9975ee5126f6c157519c6b93c212 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 13171454f959..a83beefd25f3 100644 +index c322d0c1d965..52ae06afd304 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index 13171454f959..a83beefd25f3 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.47.1 +2.51.0 -From 3aa9fc5fd7faed0bd5948e80e6ef6173c32a83ca Mon Sep 17 00:00:00 2001 +From 43b6eeeba1a611d36da3c456be538a8a72a6aaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e936019d21fe..08fee06fb5fc 100644 +index 0e4cb0e668eb..26b5515235cf 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -113,7 +113,7 @@ index e936019d21fe..08fee06fb5fc 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -168,6 +175,8 @@ struct mt_device { +@@ -171,6 +178,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -122,7 +122,7 @@ index e936019d21fe..08fee06fb5fc 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); +@@ -215,6 +224,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_GOOGLE 0x0111 #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 #define MT_CLS_SMART_TECH 0x0113 @@ -130,7 +130,7 @@ index e936019d21fe..08fee06fb5fc 100644 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -402,6 +412,16 @@ static const struct mt_class mt_classes[] = { +@@ -405,6 +415,16 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, }, @@ -147,7 +147,7 @@ index e936019d21fe..08fee06fb5fc 100644 { } }; -@@ -1751,6 +1771,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1763,6 +1783,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index e936019d21fe..08fee06fb5fc 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1774,6 +1857,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1786,6 +1869,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index e936019d21fe..08fee06fb5fc 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1812,8 +1898,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1824,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index e936019d21fe..08fee06fb5fc 100644 if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1822,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1834,8 +1922,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index e936019d21fe..08fee06fb5fc 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1873,6 +1963,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1885,6 +1975,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index e936019d21fe..08fee06fb5fc 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2299,6 +2390,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2314,6 +2405,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -272,9 +272,9 @@ index e936019d21fe..08fee06fb5fc 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.47.1 +2.51.0 -From c88ebc0ed1f21ec7ad52aa4fb2c48226603d7596 Mon Sep 17 00:00:00 2001 +From ee3127061887dc88d2b412ad23b4b592045cfee4 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 08fee06fb5fc..f6664049f46d 100644 +index 26b5515235cf..37a3e6489091 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -323,7 +323,7 @@ index 08fee06fb5fc..f6664049f46d 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -414,6 +417,7 @@ static const struct mt_class mt_classes[] = { +@@ -417,6 +420,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -413,7 +413,7 @@ index 08fee06fb5fc..f6664049f46d 100644 return 0; } -@@ -1641,6 +1687,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1648,6 +1694,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index 08fee06fb5fc..f6664049f46d 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1689,6 +1771,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1697,6 +1779,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 08fee06fb5fc..f6664049f46d 100644 default: suffix = "UNKNOWN"; break; -@@ -1771,30 +1860,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1783,30 +1872,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 08fee06fb5fc..f6664049f46d 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1803,8 +1868,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1815,8 +1880,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 08fee06fb5fc..f6664049f46d 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -1941,13 +2007,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -1953,13 +2019,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 08fee06fb5fc..f6664049f46d 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1956,12 +2033,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -1968,12 +2045,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); @@ -571,5 +571,5 @@ index 08fee06fb5fc..f6664049f46d 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index 704bdbc663..4a7b3fffe6 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,7 +1,7 @@ -From e88946a0b6535c5a7e31d30f345551df35ac1ef5 Mon Sep 17 00:00:00 2001 +From 58b71fa568056a685b913aa2eef5334707007c52 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 -Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod Work around buggy EFI firmware: On some Microsoft Surface devices (Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 35270172c833..529779994ef6 100644 +index 7e9b6e4d4695..93eefd5493e9 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,10 +37,10 @@ index 35270172c833..529779994ef6 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 8103bc24a54e..e8fa8d810925 100644 +index 18fa918b4e53..7a7613264e3c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6301,3 +6301,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6338,3 +6338,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -81,10 +81,10 @@ index 8103bc24a54e..e8fa8d810925 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 4e77c4230c0a..a4b0e6ef6cfe 100644 +index 242ee3843e10..96753fb66158 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -467,6 +467,7 @@ struct pci_dev { +@@ -482,6 +482,7 @@ struct pci_dev { unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ @@ -93,5 +93,5 @@ index 4e77c4230c0a..a4b0e6ef6cfe 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index cb83acb03c..fca2a62feb 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From 8120dc21068acfe547e9c6d1cced417e5931c7ad Mon Sep 17 00:00:00 2001 +From 6929d34532110795631fe5895a3f54a9281d7250 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index e076e492cb..14eea55744 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From 2cb3cbe91cb78a8747e6eee341c1d4e20c459d16 Mon Sep 17 00:00:00 2001 +From 93cecd009a4c3c6bb8bb649c111796098ab54bba Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,10 +58,10 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 7ecc401fb97f..e35185de1902 100644 +index ba98763ced7d..6021907ec8ba 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c -@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, +@@ -2209,6 +2209,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, static void acpi_default_enumeration(struct acpi_device *device) { @@ -72,9 +72,9 @@ index 7ecc401fb97f..e35185de1902 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.47.1 +2.51.0 -From 29efdd823d22e0a6f7dead43d9c309602a1d2cbd Mon Sep 17 00:00:00 2001 +From 1edebcabf4603be9560709d9e667f275510c158c Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index c010aebe6cc1..42b342184d56 100644 +index 65adfc813ee6..3dcabd6c5204 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -45,6 +45,13 @@ @@ -132,7 +132,7 @@ index c010aebe6cc1..42b342184d56 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -2054,6 +2063,9 @@ static int device_def_domain_type(struct device *dev) +@@ -2074,6 +2083,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index c010aebe6cc1..42b342184d56 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2354,6 +2366,9 @@ static int __init init_dmars(void) +@@ -2374,6 +2386,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index c010aebe6cc1..42b342184d56 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4664,6 +4679,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4704,6 +4719,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index c010aebe6cc1..42b342184d56 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4711,6 +4738,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4754,6 +4781,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index c010aebe6cc1..42b342184d56 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.47.1 +2.51.0 -From 503ddf1a3c915d4b1108b44a280fd588fd11252c Mon Sep 17 00:00:00 2001 +From db78c28a8c99bf160b52433e90f3b5ff54ebdd9f Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -201,7 +201,7 @@ Patchset: cameras 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 1e107fd49f82..e3e1696e7f0e 100644 +index 81ac4c691963..f453c9043042 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) @@ -219,9 +219,9 @@ index 1e107fd49f82..e3e1696e7f0e 100644 return 0; -- -2.47.1 +2.51.0 -From 46806f2df854794beb466026561dc6446ec77632 Mon Sep 17 00:00:00 2001 +From 19b281e56886842926c50addf2974a5695ec8ca4 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -243,10 +243,10 @@ Patchset: cameras 1 file changed, 15 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 3de463c3d13b..0a012eeed30a 100644 +index 9e69ac9cfb92..d6003198aa12 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -80,12 +80,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 +@@ -81,12 +81,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 const char *func, unsigned long gpio_flags) { int ret; @@ -272,12 +272,12 @@ index 3de463c3d13b..0a012eeed30a 100644 + } + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], - agpio, func, polarity); + agpio, func, gpio_flags); if (ret) -- -2.47.1 +2.51.0 -From af26f5acd84f8f7db95873690902562a159a94fb Mon Sep 17 00:00:00 2001 +From 845d4743b29b9990332528efeb50bdc3ee73d6a7 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -292,10 +292,10 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 30f61e04ecaf..9c1292ca8552 100644 +index 3226888d77e9..3bfe45b764f7 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c -@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) +@@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE: ret = ov7251_set_exposure(ov7251, ctrl->val); break; @@ -304,7 +304,7 @@ index 30f61e04ecaf..9c1292ca8552 100644 ret = ov7251_set_gain(ov7251, ctrl->val); break; case V4L2_CID_TEST_PATTERN: -@@ -1572,7 +1572,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) +@@ -1574,7 +1574,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, V4L2_CID_EXPOSURE, 1, 32, 1, 32); ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, @@ -314,9 +314,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.47.1 +2.51.0 -From d0bcf0400f018b7d505f47bcf21ef7843f1372ca Mon Sep 17 00:00:00 2001 +From 4b5519ae3d4fc3b303b6b187a5beb63fdda333d6 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -365,9 +365,9 @@ index f19c8adf2c61..923ed1b5ab8b 100644 if (ret < 0) goto out_cleanup; -- -2.47.1 +2.51.0 -From 222586440493b857e7c5aa363f8741b7fff753be Mon Sep 17 00:00:00 2001 +From 552f695429ac278fd55b325571245e111c8c96d7 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -383,7 +383,7 @@ Patchset: cameras 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index e3e1696e7f0e..423dc555093f 100644 +index f453c9043042..b8ad6b413e8b 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -395,7 +395,7 @@ index e3e1696e7f0e..423dc555093f 100644 static const struct mfd_cell tps68470_cros[] = { { .name = "tps68470-gpio" }, -@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) cells[1].name = "tps68470-regulator"; cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); @@ -406,9 +406,9 @@ index e3e1696e7f0e..423dc555093f 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.47.1 +2.51.0 -From b0e450741669b478b74d8610fd9dbae817962077 Mon Sep 17 00:00:00 2001 +From 8491189b63c62c1559497df1548863864828b75c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -447,9 +447,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.47.1 +2.51.0 -From 7f546475ba781cf67aedd9817046b506873edab1 Mon Sep 17 00:00:00 2001 +From 383b9740f8cd9ad0dc1519522975d1140fc2df43 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -698,9 +698,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.47.1 +2.51.0 -From adf794d65cca167d5bc66ef0c8a160e3fbeb3481 Mon Sep 17 00:00:00 2001 +From 205b138b1b045a9bd8fa8aeadb9aeec862c606a8 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -730,5 +730,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index 93c8956a23..385bd426e6 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From 28b8120e4f9b02ec49ccedd036557552a1aee5dc Mon Sep 17 00:00:00 2001 +From 5281dfaba9efa2cd29a0ad637fe57658ea80ecca Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 4efecac49863..88377bb0d137 100644 +index 63adda8a143f..00914222a705 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -30,9 +30,9 @@ index 4efecac49863..88377bb0d137 100644 #include +#include - #include - #include -@@ -1132,6 +1133,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + #include + +@@ -1174,6 +1175,17 @@ static void __init mp_config_acpi_legacy_irqs(void) } } @@ -50,7 +50,7 @@ index 4efecac49863..88377bb0d137 100644 /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -@@ -1187,6 +1199,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) +@@ -1229,6 +1241,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, acpi_gbl_FADT.sci_interrupt); @@ -63,9 +63,9 @@ index 4efecac49863..88377bb0d137 100644 mp_config_acpi_legacy_irqs(); -- -2.47.1 +2.51.0 -From 1b801d759aced457e5508cf931fa849400233b92 Mon Sep 17 00:00:00 2001 +From 660e2e2e671331aa89b513c8a53de6440dc6ef59 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,10 +80,10 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 88377bb0d137..c58f26918b17 100644 +index 00914222a705..2b35bb58b0e2 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -1135,12 +1135,19 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1177,12 +1177,19 @@ static void __init mp_config_acpi_legacy_irqs(void) static const struct dmi_system_id surface_quirk[] __initconst = { { @@ -105,5 +105,5 @@ index 88377bb0d137..c58f26918b17 100644 }; -- -2.47.1 +2.51.0 diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index 784921d06d..8b820d6d9d 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From 0a6b868f61d7564bc898ac30c84fbf3c34fb7368 Mon Sep 17 00:00:00 2001 +From 0033720ba60019e428c982347a491823d52f8d51 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index b831cb8e53dc..78bd0f926505 100644 +index b75ceaab716e..3dfcfd32d574 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, @@ -58,9 +58,9 @@ index b831cb8e53dc..78bd0f926505 100644 }; static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, -@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) - - pm_runtime_get_sync(dev); +@@ -568,13 +575,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + if (dd->capabilities & ACPI_TAD_RT) + sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group); + if (dd->capabilities & ACPI_TAD_AC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); @@ -79,7 +79,7 @@ index b831cb8e53dc..78bd0f926505 100644 if (dd->capabilities & ACPI_TAD_DC_WAKE) { acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); -@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) +@@ -616,12 +628,6 @@ static int acpi_tad_probe(struct platform_device *pdev) goto remove_handler; } @@ -92,7 +92,7 @@ index b831cb8e53dc..78bd0f926505 100644 dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); if (!dd) { ret = -ENOMEM; -@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) +@@ -652,6 +658,12 @@ static int acpi_tad_probe(struct platform_device *pdev) if (ret) goto fail; @@ -106,5 +106,5 @@ index b831cb8e53dc..78bd0f926505 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.47.1 +2.51.0 From 9db9d9b2e150e4473000d6383188d60f7b3ae524 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Dec 2025 22:49:17 +0100 Subject: [PATCH 142/236] pkg/fedora: Fix dependency errors --- ...1-Pull-in-iptsd-as-a-weak-dependency.patch | 8 +- ...ce-provide-the-standard-package-name.patch | 146 ++++++++++++++++-- ...ce-conflict-with-older-versions-of-t.patch | 24 +-- ...and-service-files-for-keeping-the-su.patch | 18 +-- .../0005-Pull-in-intel-vsc-firmware.patch | 8 +- 5 files changed, 165 insertions(+), 39 deletions(-) diff --git a/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch index 95a0b2c071..69507ef889 100644 --- a/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch +++ b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch @@ -1,4 +1,4 @@ -From 83a53f9f9e17797d5bb0a2eeb5208533d921b6d6 Mon Sep 17 00:00:00 2001 +From 85bd89ed2f2310e99a0c4f291e02dcba08383570 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:33:03 +0200 Subject: [PATCH 1/5] Pull in iptsd as a weak dependency @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index bbe58bf955f0..9f48a4e6c91f 100644 +index 08ff3553cecc..042a9736e324 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1178,6 +1178,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1191,6 +1191,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index bbe58bf955f0..9f48a4e6c91f 100644 Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -- -2.51.0 +2.52.0 diff --git a/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch index 138f515edd..3db31957fd 100644 --- a/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch +++ b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch @@ -1,18 +1,18 @@ -From b613bdf0b0520f8046cb837184b56946b5676002 Mon Sep 17 00:00:00 2001 +From 33d5f8140694dd1c6e033fbf310c7c7785f07c90 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:09:20 +0200 Subject: [PATCH 2/5] Let kernel-surface provide the standard package names Signed-off-by: Dorian Stoll --- - redhat/kernel.spec.template | 5 +++++ - 1 file changed, 5 insertions(+) + redhat/kernel.spec.template | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 9f48a4e6c91f..e6ef25cb0580 100644 +index 042a9736e324..23ed1c854ed4 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -734,6 +734,7 @@ Requires: %{name}-modules-uname-r = %{KVERREL} +@@ -747,6 +747,7 @@ Requires: %{name}-modules-uname-r = %{KVERREL} Requires: %{name}-modules-core-uname-r = %{KVERREL} Requires: ((%{name}-modules-extra-uname-r = %{KVERREL}) if %{name}-modules-extra-matched) Provides: installonlypkg(kernel) @@ -20,7 +20,47 @@ index 9f48a4e6c91f..e6ef25cb0580 100644 %endif -@@ -1484,6 +1485,7 @@ Provides: %{name}%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release} +@@ -1184,7 +1185,9 @@ The %{package_name} meta package + Provides: kernel = %{specversion}-%{pkg_release}\ + Provides: %{name} = %{specversion}-%{pkg_release}\ + %endif\ ++Provides: kernel-%{_target_cpu} = %{specrpmversion}-%{pkg_release}%{uname_suffix %{?1}}\ + Provides: %{name}-%{_target_cpu} = %{specrpmversion}-%{pkg_release}%{uname_suffix %{?1}}\ ++Provides: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires(pre): %{kernel_prereq}\ +@@ -1223,6 +1226,7 @@ Summary: Header files for the Linux kernel for use by glibc + Obsoletes: glibc-kernheaders < 3.0-46 + Provides: glibc-kernheaders = 3.0-46 + %if 0%{?gemini} ++Provides: kernel-headers = %{specversion}-%{release} + Provides: %{name}-headers = %{specversion}-%{release} + Obsoletes: kernel-headers < %{specversion} + %endif +@@ -1238,6 +1242,7 @@ glibc package. + %package cross-headers + Summary: Header files for the Linux kernel for use by cross-glibc + %if 0%{?gemini} ++Provides: kernel-cross-headers = %{specversion}-%{release} + Provides: %{name}-cross-headers = %{specversion}-%{release} + Obsoletes: kernel-cross-headers < %{specversion} + %endif +@@ -1477,6 +1482,7 @@ Linux kernel, suitable for the kabi-dw tool. + %package %{?1:%{1}-}debuginfo\ + Summary: Debug information for package %{name}%{?1:-%{1}}\ + Requires: %{name}-debuginfo-common-%{_target_cpu} = %{specrpmversion}-%{release}\ ++Provides: kernel%{?1:-%{1}}-debuginfo-%{_target_cpu} = %{specrpmversion}-%{release}\ + Provides: %{name}%{?1:-%{1}}-debuginfo-%{_target_cpu} = %{specrpmversion}-%{release}\ + Provides: installonlypkg(kernel)\ + AutoReqProv: no\ +@@ -1493,10 +1499,13 @@ This is required to use SystemTap with %{name}%{?1:-%{1}}-%{KVERREL}.\ + %define kernel_devel_package(m) \ + %package %{?1:%{1}-}devel\ + Summary: Development package for building kernel modules to match the %{?2:%{2} }kernel\ ++Provides: kernel%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release}\ + Provides: %{name}%{?1:-%{1}}-devel-%{_target_cpu} = %{specrpmversion}-%{release}\ ++Provides: kernel-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ Provides: %{name}-devel-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ @@ -28,7 +68,7 @@ index 9f48a4e6c91f..e6ef25cb0580 100644 Provides: installonlypkg(kernel)\ AutoReqProv: no\ Requires(pre): findutils\ -@@ -1513,6 +1515,7 @@ against the %{?2:%{2} }kernel package.\ +@@ -1526,6 +1535,7 @@ against the %{?2:%{2} }kernel package.\ Summary: Meta package to install matching core and devel packages for a given %{?2:%{2} }kernel\ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ @@ -36,7 +76,67 @@ index 9f48a4e6c91f..e6ef25cb0580 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1630,6 +1633,7 @@ Requires: ((%{name}-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) +@@ -1545,10 +1555,14 @@ This meta package provides a single reference that other packages can Require to + %package %{?1:%{1}-}modules-internal\ + Summary: Extra kernel modules to match the %{?2:%{2} }kernel\ + Group: System Environment/Kernel\ ++Provides: kernel%{?1:-%{1}}-modules-internal-%{_target_cpu} = %{specrpmversion}-%{release}\ + Provides: %{name}%{?1:-%{1}}-modules-internal-%{_target_cpu} = %{specrpmversion}-%{release}\ ++Provides: kernel%{?1:-%{1}}-modules-internal-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-internal-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ ++Provides: kernel%{?1:-%{1}}-modules-internal = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-internal = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: installonlypkg(kernel-module)\ ++Provides: kernel%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +@@ -1566,10 +1580,14 @@ This package provides kernel modules for the %{?2:%{2} }kernel package for Red H + %define kernel_modules_extra_package(m) \ + %package %{?1:%{1}-}modules-extra\ + Summary: Extra kernel modules to match the %{?2:%{2} }kernel\ ++Provides: kernel%{?1:-%{1}}-modules-extra-%{_target_cpu} = %{specrpmversion}-%{release}\ + Provides: %{name}%{?1:-%{1}}-modules-extra-%{_target_cpu} = %{specrpmversion}-%{release}\ ++Provides: kernel%{?1:-%{1}}-modules-extra-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-extra-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ ++Provides: kernel%{?1:-%{1}}-modules-extra = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-extra = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: installonlypkg(kernel-module)\ ++Provides: kernel%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +@@ -1590,10 +1608,14 @@ This package provides less commonly used kernel modules for the %{?2:%{2} }kerne + %define kernel_modules_package(m) \ + %package %{?1:%{1}-}modules\ + Summary: kernel modules to match the %{?2:%{2}-}core kernel\ ++Provides: kernel%{?1:-%{1}}-modules-%{_target_cpu} = %{specrpmversion}-%{release}\ + Provides: %{name}%{?1:-%{1}}-modules-%{_target_cpu} = %{specrpmversion}-%{release}\ ++Provides: kernel-modules-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}-modules-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ ++Provides: kernel-modules = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}-modules = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: installonlypkg(kernel-module)\ ++Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +@@ -1613,10 +1635,14 @@ This package provides commonly used kernel modules for the %{?2:%{2}-}core kerne + %define kernel_modules_core_package(m) \ + %package %{?1:%{1}-}modules-core\ + Summary: Core kernel modules to match the %{?2:%{2}-}core kernel\ ++Provides: kernel%{?1:-%{1}}-modules-core-%{_target_cpu} = %{specrpmversion}-%{release}\ + Provides: %{name}%{?1:-%{1}}-modules-core-%{_target_cpu} = %{specrpmversion}-%{release}\ ++Provides: kernel-modules-core-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}-modules-core-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ ++Provides: kernel-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: installonlypkg(kernel-module)\ ++Provides: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + %if %{-m:1}%{!-m:0}\ +@@ -1643,6 +1669,7 @@ Requires: ((%{name}-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) Requires: realtime-setup\ %endif\ Provides: installonlypkg(kernel)\ @@ -44,14 +144,40 @@ index 9f48a4e6c91f..e6ef25cb0580 100644 %description %{1}\ The meta-package for the %{1} kernel\ %{nil} -@@ -1648,6 +1652,7 @@ The meta-package for the %{1} kernel\ +@@ -1659,8 +1686,10 @@ The meta-package for the %{1} kernel\ + %define kernel_variant_package(n:mo) \ + %package %{?1:%{1}-}core\ Summary: %{variant_summary}\ ++Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ +Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{uname_suffix %{?1}}\ %if %{-m:1}%{!-m:0}\ Requires: %{name}-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ +@@ -1685,6 +1714,7 @@ Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant % + %package %{?1:%{1}-}uki-virt\ + Summary: %{variant_summary} unified kernel image for virtual machines\ + Provides: installonlypkg(kernel)\ ++Provides: kernel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires(pre): %{kernel_prereq}\ +@@ -1709,10 +1739,14 @@ Requires(pre): systemd >= 254-1\ + %package %{?1:%{1}-}modules-partner\ + Summary: Extra kernel modules to match the %{?2:%{2} }kernel\ + Group: System Environment/Kernel\ ++Provides: kernel%{?1:-%{1}}-modules-partner-%{_target_cpu} = %{specrpmversion}-%{release}\ + Provides: %{name}%{?1:-%{1}}-modules-partner-%{_target_cpu} = %{specrpmversion}-%{release}\ ++Provides: kernel%{?1:-%{1}}-modules-partner-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-partner-%{_target_cpu} = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ ++Provides: kernel%{?1:-%{1}}-modules-partner = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-partner = %{specrpmversion}-%{release}%{uname_suffix %{?1}}\ + Provides: installonlypkg(kernel-module)\ ++Provides: kernel%{?1:-%{1}}-modules-partner-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Provides: %{name}%{?1:-%{1}}-modules-partner-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ + Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ -- -2.51.0 +2.52.0 diff --git a/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch index 354dafd00f..bf496ffea1 100644 --- a/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch +++ b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch @@ -1,4 +1,4 @@ -From 32f4f4868f746f57d765561035e9768da1f89138 Mon Sep 17 00:00:00 2001 +From 9cfe9cb267c9ba855738b6474c22f95ac4445b07 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:10:38 +0200 Subject: [PATCH 3/5] Let kernel-surface conflict with older versions of the @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 18 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index e6ef25cb0580..2211bde2aa5a 100644 +index 23ed1c854ed4..81bb35bb8e36 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -735,6 +735,10 @@ Requires: %{name}-modules-core-uname-r = %{KVERREL} +@@ -748,6 +748,10 @@ Requires: %{name}-modules-core-uname-r = %{KVERREL} Requires: ((%{name}-modules-extra-uname-r = %{KVERREL}) if %{name}-modules-extra-matched) Provides: installonlypkg(kernel) Provides: kernel = %{KVERREL} @@ -24,7 +24,7 @@ index e6ef25cb0580..2211bde2aa5a 100644 %endif -@@ -1487,6 +1491,8 @@ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +@@ -1507,6 +1511,8 @@ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: kernel-devel = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ @@ -33,7 +33,7 @@ index e6ef25cb0580..2211bde2aa5a 100644 AutoReqProv: no\ Requires(pre): findutils\ Requires: findutils\ -@@ -1516,6 +1522,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ +@@ -1536,6 +1542,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ Provides: kernel-devel-matched = %{specrpmversion}-%{release}\ @@ -42,7 +42,7 @@ index e6ef25cb0580..2211bde2aa5a 100644 %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1564,6 +1572,8 @@ Provides: %{name}%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{ +@@ -1592,6 +1600,8 @@ Provides: %{name}%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ @@ -51,7 +51,7 @@ index e6ef25cb0580..2211bde2aa5a 100644 %if %{-m:1}%{!-m:0}\ Requires: %{name}-modules-extra-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1587,6 +1597,8 @@ Provides: installonlypkg(kernel-module)\ +@@ -1619,6 +1629,8 @@ Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ @@ -60,8 +60,8 @@ index e6ef25cb0580..2211bde2aa5a 100644 %if %{-m:1}%{!-m:0}\ Requires: %{name}-modules-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1609,6 +1621,8 @@ Provides: %{name}-modules-core = %{specrpmversion}-%{release}%{uname_suffix %{?1 - Provides: installonlypkg(kernel-module)\ +@@ -1645,6 +1657,8 @@ Provides: installonlypkg(kernel-module)\ + Provides: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +Conflicts: %{package_name}-modules-core < 6.3.7-2\ @@ -69,7 +69,7 @@ index e6ef25cb0580..2211bde2aa5a 100644 %if %{-m:1}%{!-m:0}\ Requires: %{name}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1632,6 +1646,8 @@ Requires: ((%{name}-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) +@@ -1668,6 +1682,8 @@ Requires: ((%{name}-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) %if "%{1}" == "rt" || "%{1}" == "rt-debug" || "%{1}" == "rt-64k" || "%{1}" == "rt-64k-debug"\ Requires: realtime-setup\ %endif\ @@ -78,7 +78,7 @@ index e6ef25cb0580..2211bde2aa5a 100644 Provides: installonlypkg(kernel)\ Provides: kernel = %{KVERREL}+%{1}\ %description %{1}\ -@@ -1653,6 +1669,8 @@ Summary: %{variant_summary}\ +@@ -1690,6 +1706,8 @@ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{uname_suffix %{?1}}\ @@ -88,5 +88,5 @@ index e6ef25cb0580..2211bde2aa5a 100644 Requires: %{name}-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ -- -2.51.0 +2.52.0 diff --git a/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch index f62a58e375..816e0d500a 100644 --- a/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch +++ b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch @@ -1,4 +1,4 @@ -From 76a02768150ead36dde30f77294cf4fd8bef06d2 Mon Sep 17 00:00:00 2001 +From 2a2842c01b07268627d47ef2f12377a19a34e093 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:12:29 +0200 Subject: [PATCH 4/5] Install scripts and service files for keeping the surface @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 33 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 2211bde2aa5a..561ae802e34f 100644 +index 81bb35bb8e36..67aaf5883051 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1148,6 +1148,11 @@ Source4000: README.rst +@@ -1161,6 +1161,11 @@ Source4000: README.rst Source4001: rpminspect.yaml Source4002: gating.yaml @@ -25,7 +25,7 @@ index 2211bde2aa5a..561ae802e34f 100644 ## Patches needed for building this package %if !%{nopatches} -@@ -1184,6 +1189,7 @@ Requires(pre): %{initrd_prereq}\ +@@ -1199,6 +1204,7 @@ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ Recommends: iptsd\ @@ -33,7 +33,7 @@ index 2211bde2aa5a..561ae802e34f 100644 Requires(preun): systemd >= 200\ Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -@@ -1198,6 +1204,13 @@ AutoProv: yes\ +@@ -1213,6 +1219,13 @@ AutoProv: yes\ %{nil} @@ -47,7 +47,7 @@ index 2211bde2aa5a..561ae802e34f 100644 %package doc Summary: Various documentation bits found in the kernel source Group: Documentation -@@ -3447,6 +3460,11 @@ find Documentation -type d | xargs chmod u+w +@@ -3475,6 +3488,11 @@ find Documentation -type d | xargs chmod u+w cd linux-%{KVERREL} @@ -59,7 +59,7 @@ index 2211bde2aa5a..561ae802e34f 100644 # re-define RPM_VMLINUX_H, because it doesn't carry over from %build RPM_VMLINUX_H="$(cat ../vmlinux_h_path)" -@@ -3750,6 +3768,15 @@ popd +@@ -3784,6 +3802,15 @@ popd ### scripts ### @@ -75,7 +75,7 @@ index 2211bde2aa5a..561ae802e34f 100644 %if %{with_tools} %post -n %{package_name}-tools-libs /sbin/ldconfig -@@ -4222,6 +4249,12 @@ fi\ +@@ -4266,6 +4293,12 @@ fi\ %{_libexecdir}/kselftests %endif @@ -89,5 +89,5 @@ index 2211bde2aa5a..561ae802e34f 100644 %if %{with_up_base} %ifnarch %nobuildarches noarch -- -2.51.0 +2.52.0 diff --git a/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch index 12340dd664..dcb561e324 100644 --- a/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch +++ b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch @@ -1,4 +1,4 @@ -From f6344afdfee91f53c535288b0e47818779360129 Mon Sep 17 00:00:00 2001 +From 8f14c27edbb29fdc927168d41174dc5a4b9f80db Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:14:00 +0200 Subject: [PATCH 5/5] Pull in intel-vsc-firmware @@ -9,10 +9,10 @@ This package contains the IPU3 firmware needed for camera support. 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 561ae802e34f..e2c9ffe3c52e 100644 +index 67aaf5883051..79e67a8b1440 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1188,6 +1188,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1203,6 +1203,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index 561ae802e34f..e2c9ffe3c52e 100644 Recommends: %{package_name}-default-watchdog\ Requires(preun): systemd >= 200\ -- -2.51.0 +2.52.0 From 678eeb11f7309c51d07ba94c65c34b0de235207b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Dec 2025 22:51:40 +0100 Subject: [PATCH 143/236] Update v6.17 patches Changes: - Rebase onto v6.17.13 --- patches/6.17/0001-secureboot.patch | 14 +++---- patches/6.17/0002-surface3.patch | 4 +- patches/6.17/0003-mwifiex.patch | 18 ++++----- patches/6.17/0004-ath10k.patch | 14 +++---- patches/6.17/0005-ipts.patch | 12 +++--- patches/6.17/0006-ithc.patch | 4 +- patches/6.17/0007-surface-sam.patch | 4 +- patches/6.17/0008-surface-sam-over-hid.patch | 4 +- patches/6.17/0009-surface-button.patch | 4 +- patches/6.17/0010-surface-typecover.patch | 42 ++++++++++---------- patches/6.17/0011-surface-shutdown.patch | 10 ++--- patches/6.17/0012-surface-gpe.patch | 2 +- patches/6.17/0013-cameras.patch | 24 +++++------ patches/6.17/0014-amd-gpio.patch | 4 +- patches/6.17/0015-rtc.patch | 14 +++---- 15 files changed, 87 insertions(+), 87 deletions(-) diff --git a/patches/6.17/0001-secureboot.patch b/patches/6.17/0001-secureboot.patch index 741a06a348..5a7324937c 100644 --- a/patches/6.17/0001-secureboot.patch +++ b/patches/6.17/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 79b500c983f2399294fca8bcd153b50a955d0aa1 Mon Sep 17 00:00:00 2001 +From 9f986ecbf39f14cf5777227d6ef6db57c657b253 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 -- 2.51.0 -From 8447597cf4fbb341325e07ef2a75d92393a15f29 Mon Sep 17 00:00:00 2001 +From 7678fd13a6f86c4f58b733a79e8bf5396133b70b Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 5a7a83c411e9..f67ddee8c4b4 100644 +index e92c0056e4e0..02f765f275ca 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3298,6 +3298,11 @@ @@ -69,7 +69,7 @@ index 5a7a83c411e9..f67ddee8c4b4 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 2f66ab453823..bb9e800b3374 100644 +index 53166ef86ba4..5b33262b17b5 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -38,6 +38,7 @@ @@ -80,7 +80,7 @@ index 2f66ab453823..bb9e800b3374 100644 static int nocompress; static int noresume; static int nohibernate; -@@ -98,7 +99,7 @@ bool hibernation_in_progress(void) +@@ -109,7 +110,7 @@ bool hibernation_in_progress(void) bool hibernation_available(void) { return nohibernate == 0 && @@ -89,7 +89,7 @@ index 2f66ab453823..bb9e800b3374 100644 !secretmem_active() && !cxl_mem_active(); } -@@ -1483,6 +1484,12 @@ static int __init nohibernate_setup(char *str) +@@ -1492,6 +1493,12 @@ static int __init nohibernate_setup(char *str) return 1; } @@ -102,7 +102,7 @@ index 2f66ab453823..bb9e800b3374 100644 static const char * const comp_alg_enabled[] = { #if IS_ENABLED(CONFIG_CRYPTO_LZO) COMPRESSION_ALGO_LZO, -@@ -1540,3 +1547,4 @@ __setup("hibernate=", hibernate_setup); +@@ -1549,3 +1556,4 @@ __setup("hibernate=", hibernate_setup); __setup("resumewait", resumewait_setup); __setup("resumedelay=", resumedelay_setup); __setup("nohibernate", nohibernate_setup); diff --git a/patches/6.17/0002-surface3.patch b/patches/6.17/0002-surface3.patch index 0850ad8df4..1279854d8c 100644 --- a/patches/6.17/0002-surface3.patch +++ b/patches/6.17/0002-surface3.patch @@ -1,4 +1,4 @@ -From 47044a281bffc78cc1f3bb9859e098e2678c55ff Mon Sep 17 00:00:00 2001 +From d8699c97930721725f42472feefc91ece4f6f45d Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.51.0 -From f4ac64d3cfabf7aef3ba9465df2c4237853a461b Mon Sep 17 00:00:00 2001 +From 9bfd71c1927f31059a4edef27a0eaf8e507a28d0 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.17/0003-mwifiex.patch b/patches/6.17/0003-mwifiex.patch index 0cf2a91b38..bda22d5841 100644 --- a/patches/6.17/0003-mwifiex.patch +++ b/patches/6.17/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From c8cd7b083a416fd1e271673a99b9803ad81fec99 Mon Sep 17 00:00:00 2001 +From f9cbe41699012e3802f813f692e74c79ad1a1c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.51.0 -From 32b04d17da87e550fa7dfa3c8900bf0d54e26285 Mon Sep 17 00:00:00 2001 +From 49f5c1a53f5679011fc7f135a38593393fa8d3fb Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.51.0 -From f01145c4f95b75eaf6610281143cbce63ca5d98e Mon Sep 17 00:00:00 2001 +From 23dc291355b16ee49055464ea4d8bd4095058988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,18 +356,18 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 8085fabadde8..315cb98b324e 100644 +index fa683bb7f0b4..f80e194aa970 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c -@@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; - #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) +@@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) #define BTUSB_ACTIONS_SEMI BIT(27) -+#define BTUSB_LOWER_LESCAN_INTERVAL BIT(28) + #define BTUSB_BARROT BIT(28) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(29) static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ -@@ -471,6 +472,7 @@ static const struct usb_device_id quirks_table[] = { +@@ -472,6 +473,7 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, @@ -375,7 +375,7 @@ index 8085fabadde8..315cb98b324e 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4129,6 +4131,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4177,6 +4179,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; diff --git a/patches/6.17/0004-ath10k.patch b/patches/6.17/0004-ath10k.patch index 4952aa84ec..9ffa08b237 100644 --- a/patches/6.17/0004-ath10k.patch +++ b/patches/6.17/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 0f6d06101eefd596f349162daee7203a6d5ad61d Mon Sep 17 00:00:00 2001 +From 9f52e06199405c2511325a784db7d4605a2191c1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,10 +20,10 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 6f78f1752cd6..8f7be9cf8a9d 100644 +index 9ae3595fb698..b26a39c97998 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -42,6 +42,9 @@ static bool fw_diag_log; +@@ -41,6 +41,9 @@ static bool fw_diag_log; /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; @@ -33,7 +33,7 @@ index 6f78f1752cd6..8f7be9cf8a9d 100644 unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); -@@ -54,6 +57,9 @@ module_param(fw_diag_log, bool, 0644); +@@ -53,6 +56,9 @@ module_param(fw_diag_log, bool, 0644); module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); @@ -43,7 +43,7 @@ index 6f78f1752cd6..8f7be9cf8a9d 100644 MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); -@@ -63,6 +69,9 @@ MODULE_PARM_DESC(frame_mode, +@@ -62,6 +68,9 @@ MODULE_PARM_DESC(frame_mode, MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); @@ -53,7 +53,7 @@ index 6f78f1752cd6..8f7be9cf8a9d 100644 static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA988X_HW_2_0_VERSION, -@@ -933,6 +942,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) +@@ -932,6 +941,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) return 0; } @@ -96,7 +96,7 @@ index 6f78f1752cd6..8f7be9cf8a9d 100644 static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, const char *dir, const char *file) -@@ -947,6 +992,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, +@@ -946,6 +991,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, if (dir == NULL) dir = "."; diff --git a/patches/6.17/0005-ipts.patch b/patches/6.17/0005-ipts.patch index 2ec5e93ba4..be7f508306 100644 --- a/patches/6.17/0005-ipts.patch +++ b/patches/6.17/0005-ipts.patch @@ -1,4 +1,4 @@ -From c4e655d712504f5d756f45541f2fdcb3707cd6c1 Mon Sep 17 00:00:00 2001 +From 702e4e0f0f82993157310d22b73e9ece119125b4 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index bc40b940ae21..45fbd856d416 100644 +index a4f75dc36929..e4a561b257d7 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index bc40b940ae21..45fbd856d416 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 3f9c60b579ae..853a67753333 100644 +index bc0fc584a8e4..51a91ef66cda 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -37,7 +37,7 @@ index 3f9c60b579ae..853a67753333 100644 -- 2.51.0 -From 6d3a8407644210b599bd5cd7bf10942ad7204fcc Mon Sep 17 00:00:00 2001 +From dc61b222997c8a6d8b8753cbcb91c1373b31f227 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index dff2d895b8ab..dc95cb3375fe 100644 +index e236c7ec221f..9e31a5fe1f66 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -144,7 +144,7 @@ index dff2d895b8ab..dc95cb3375fe 100644 -- 2.51.0 -From c3091f09b9deb8831412f84c13462ab04b86622e Mon Sep 17 00:00:00 2001 +From 841a09e0a458128d888a94118983406352f94256 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.17/0006-ithc.patch b/patches/6.17/0006-ithc.patch index 89b9a6f22a..1c069e771b 100644 --- a/patches/6.17/0006-ithc.patch +++ b/patches/6.17/0006-ithc.patch @@ -1,4 +1,4 @@ -From 48882c74dd11fe6ce6927c50d694d7dc3cdfc46f Mon Sep 17 00:00:00 2001 +From 4673894d99bcc8772535d42b2bee21fea544bb4d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 4f9b01dc91e8..e4d73e45473c 100644 -- 2.51.0 -From c49156368b0af34f99dddff87eec0c70a5af7a3e Mon Sep 17 00:00:00 2001 +From 76846a0bd73bdd9331670be1f5006f2913500e7e Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.17/0007-surface-sam.patch b/patches/6.17/0007-surface-sam.patch index 518e852538..cd60cc0641 100644 --- a/patches/6.17/0007-surface-sam.patch +++ b/patches/6.17/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 487f40f72255d0ac23f35612c40812869b97f2c1 Mon Sep 17 00:00:00 2001 +From d0a0f26ef063c7b5fec2c3a1b8ae1cd45ba4bba2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.51.0 -From 9977281edd9310d64900a4d4c1709823019b9a47 Mon Sep 17 00:00:00 2001 +From 9cbed80f9cd071c2ffdd63590cf0d232612877dc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.17/0008-surface-sam-over-hid.patch b/patches/6.17/0008-surface-sam-over-hid.patch index 56c0f42b65..99e3b23c41 100644 --- a/patches/6.17/0008-surface-sam-over-hid.patch +++ b/patches/6.17/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From f8c0ddcb0164e1a1702102ce13bf5e09568d5c0a Mon Sep 17 00:00:00 2001 +From 170d5fdab278878e6f94ade5988592fd988cf0fb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a27b7..070c36637811 100644 -- 2.51.0 -From 7f1e39bb740f65df743017db3196d5029bd3ffa3 Mon Sep 17 00:00:00 2001 +From 1d7ce37d06481d6c9ce1c019788a64b86cf946b4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.17/0009-surface-button.patch b/patches/6.17/0009-surface-button.patch index 717e196815..76d2adb6ed 100644 --- a/patches/6.17/0009-surface-button.patch +++ b/patches/6.17/0009-surface-button.patch @@ -1,4 +1,4 @@ -From e510633b5a7258dcc54cf166d7c994dc867fedda Mon Sep 17 00:00:00 2001 +From 1a9bb05cc275049ad39b4e2db2c740e25482a249 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.51.0 -From 462ebc6ad95ead44113459c7c20d0612e1af5e11 Mon Sep 17 00:00:00 2001 +From ccc1fc9362ec228d5821d9c5578eeaa90d9db42b Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.17/0010-surface-typecover.patch b/patches/6.17/0010-surface-typecover.patch index b510a6458f..f0719ba14b 100644 --- a/patches/6.17/0010-surface-typecover.patch +++ b/patches/6.17/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 9b522924acc63d21b9ea6df651c2dcb04f294034 Mon Sep 17 00:00:00 2001 +From 937c654057091ab9efc529ad44ac116251974fb9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index f5bc53875330..31fa895d73c4 100644 +index 47f589c4104a..6b00aec67ee2 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -39,7 +39,7 @@ index f5bc53875330..31fa895d73c4 100644 -- 2.51.0 -From 5f558fb565ae75a0bebe6ae74c1f699bbe3accae Mon Sep 17 00:00:00 2001 +From d5768e0e9b7b9fe1274170b6c4e2a62e508a2f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 22c6314a8843..062c9de23db9 100644 +index a9ff84f0bd9b..1b2fc88ce1cf 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -113,7 +113,7 @@ index 22c6314a8843..062c9de23db9 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -177,6 +184,8 @@ struct mt_device { +@@ -180,6 +187,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -122,7 +122,7 @@ index 22c6314a8843..062c9de23db9 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -222,6 +231,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); +@@ -225,6 +234,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 #define MT_CLS_SMART_TECH 0x0113 #define MT_CLS_APPLE_TOUCHBAR 0x0114 @@ -130,7 +130,7 @@ index 22c6314a8843..062c9de23db9 100644 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -418,6 +428,16 @@ static const struct mt_class mt_classes[] = { +@@ -421,6 +431,16 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, }, @@ -147,7 +147,7 @@ index 22c6314a8843..062c9de23db9 100644 { } }; -@@ -1809,6 +1829,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1811,6 +1831,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index 22c6314a8843..062c9de23db9 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1832,6 +1915,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1834,6 +1917,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index 22c6314a8843..062c9de23db9 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1870,8 +1956,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1872,8 +1958,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index 22c6314a8843..062c9de23db9 100644 if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && !hid_find_field(hdev, HID_INPUT_REPORT, -@@ -1885,8 +1973,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1887,8 +1975,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index 22c6314a8843..062c9de23db9 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1936,6 +2026,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1938,6 +2028,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index 22c6314a8843..062c9de23db9 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2380,6 +2471,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2382,6 +2473,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, @@ -274,7 +274,7 @@ index 22c6314a8843..062c9de23db9 100644 -- 2.51.0 -From 4d38f704475f87a6ec40f3b2ba2184da867c5d55 Mon Sep 17 00:00:00 2001 +From 9ab3ab41c4292e3877f81a960147521b9c29a935 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 062c9de23db9..487364959ab5 100644 +index 1b2fc88ce1cf..dd200064e309 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -79,6 +79,7 @@ MODULE_LICENSE("GPL"); @@ -323,7 +323,7 @@ index 062c9de23db9..487364959ab5 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -430,6 +433,7 @@ static const struct mt_class mt_classes[] = { +@@ -433,6 +436,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -456,7 +456,7 @@ index 062c9de23db9..487364959ab5 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1744,6 +1826,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1745,6 +1827,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 062c9de23db9..487364959ab5 100644 default: suffix = "UNKNOWN"; break; -@@ -1829,30 +1918,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1831,30 +1920,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 062c9de23db9..487364959ab5 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1861,8 +1926,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1863,8 +1928,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 062c9de23db9..487364959ab5 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -2004,13 +2070,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -2006,13 +2072,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 062c9de23db9..487364959ab5 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -2019,12 +2096,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -2021,12 +2098,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); diff --git a/patches/6.17/0011-surface-shutdown.patch b/patches/6.17/0011-surface-shutdown.patch index bb2c37c240..6554315a1a 100644 --- a/patches/6.17/0011-surface-shutdown.patch +++ b/patches/6.17/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 269ce75e30d184b81b8b40bb0c1bee28abe95082 Mon Sep 17 00:00:00 2001 +From 3233e846799f63d18bfafbc1d41bc65fbd337609 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 63665240ae87..727364643822 100644 +index 302d61783f6c..4a8a08bd92dd 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,10 +37,10 @@ index 63665240ae87..727364643822 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index d97335a40193..89184a0fb679 100644 +index 214ed060ca1b..104fba45ac76 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6338,3 +6338,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6339,3 +6339,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -81,7 +81,7 @@ index d97335a40193..89184a0fb679 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 59876de13860..41d0a274a550 100644 +index 7735acf6f349..27780b0f1115 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -484,6 +484,7 @@ struct pci_dev { diff --git a/patches/6.17/0012-surface-gpe.patch b/patches/6.17/0012-surface-gpe.patch index 1bbc7a494a..a9c5f65a86 100644 --- a/patches/6.17/0012-surface-gpe.patch +++ b/patches/6.17/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 07f651aa185f63d3dfb917e0083ba1b0e28157c0 Mon Sep 17 00:00:00 2001 +From 8a8c257440871504b48739fcd4719049638178f6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.17/0013-cameras.patch b/patches/6.17/0013-cameras.patch index 3eede56de2..e5300bbe72 100644 --- a/patches/6.17/0013-cameras.patch +++ b/patches/6.17/0013-cameras.patch @@ -1,4 +1,4 @@ -From 365e0d66f4e0f3681795b63db37ebf14f8e2fdf2 Mon Sep 17 00:00:00 2001 +From 93a40ae9e889a11730e7e616bb313d6dc7d5a5dc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,10 +58,10 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index fb1fe9f3b1a3..5be8893b3912 100644 +index f2e032f38162..c45820be8fd0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c -@@ -2197,6 +2197,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, +@@ -2201,6 +2201,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, static void acpi_default_enumeration(struct acpi_device *device) { @@ -74,7 +74,7 @@ index fb1fe9f3b1a3..5be8893b3912 100644 -- 2.51.0 -From 90cb7694c399c63d5c6c44aba0ee1cb048c6355d Mon Sep 17 00:00:00 2001 +From c552e13ba9c4e725c8ab68016affe3697a7102d5 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index dc95cb3375fe..8c900fce80d1 100644 +index 9e31a5fe1f66..bdd32551c452 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -184,7 +184,7 @@ index dc95cb3375fe..8c900fce80d1 100644 -- 2.51.0 -From ad0067a390921345f7c43779b102f43f3b587f4c Mon Sep 17 00:00:00 2001 +From 9868645027474ea4be300614971df7bf4fbe0e4a Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.51.0 -From e80f10566f351ea0de98d606a6bbc8c8089a7712 Mon Sep 17 00:00:00 2001 +From add99db7db117172d47c6a3feb318cb83ab7b535 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 31a42d81e970..0d5a8fd86e67 100644 -- 2.51.0 -From c7942343d69b7a0dd2868a27ddda3c49b528b784 Mon Sep 17 00:00:00 2001 +From 4983fa30433b34386e8d43e72e348a00b3d0ef9d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.51.0 -From 2a087a81397c2ac9a79a7861e553a40e69eb2aae Mon Sep 17 00:00:00 2001 +From 6a40dbaaa72f332b416a2722b93d22f4e7341ad7 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.51.0 -From 0258799a71d332c75235d50e2ca799863d803508 Mon Sep 17 00:00:00 2001 +From 501f49d48266ee52109f35a50c7a63a7190d5bff Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.51.0 -From fd36497dcf8f79d5e5c9dd8b4088d3fb694ee799 Mon Sep 17 00:00:00 2001 +From 93f9dbec991c78763d0abdf567539691b9ef3cab Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.51.0 -From 4c7a0198b0d3e3e8f074df6cc7841452dd35cd68 Mon Sep 17 00:00:00 2001 +From 82a0860d4f7b8226e21577a3956f620d3bbca6c2 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.17/0014-amd-gpio.patch b/patches/6.17/0014-amd-gpio.patch index 8ccb4c1988..7eb3046197 100644 --- a/patches/6.17/0014-amd-gpio.patch +++ b/patches/6.17/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From c8e851f02c44501c75d205fb97dfb3601342cca1 Mon Sep 17 00:00:00 2001 +From 87bbb9dd149bc1a198f5ceddf87f4f5da21d7525 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95eb3..8914a922be2b 100644 -- 2.51.0 -From fd6d2bcfe7ffea0f62054271788b5482818e13ec Mon Sep 17 00:00:00 2001 +From 394d72f5f5dd648258ade2875c2f066aa60cb2e7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.17/0015-rtc.patch b/patches/6.17/0015-rtc.patch index fa783e1b42..630f56f6c4 100644 --- a/patches/6.17/0015-rtc.patch +++ b/patches/6.17/0015-rtc.patch @@ -1,4 +1,4 @@ -From 1069b63e699910262e7cbc208701c9184075244d Mon Sep 17 00:00:00 2001 +From c622f89197367a28d3fd8f456dcf36621f5c1ac0 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 91d7d90c47da..94107bf62251 100644 +index 33418dd6768a..f94bbdc1de06 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, @@ -58,9 +58,9 @@ index 91d7d90c47da..94107bf62251 100644 }; static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, -@@ -565,13 +572,18 @@ static void acpi_tad_remove(struct platform_device *pdev) - - pm_runtime_get_sync(dev); +@@ -568,13 +575,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + if (dd->capabilities & ACPI_TAD_RT) + sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group); + if (dd->capabilities & ACPI_TAD_AC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); @@ -79,7 +79,7 @@ index 91d7d90c47da..94107bf62251 100644 if (dd->capabilities & ACPI_TAD_DC_WAKE) { acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); -@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) +@@ -616,12 +628,6 @@ static int acpi_tad_probe(struct platform_device *pdev) goto remove_handler; } @@ -92,7 +92,7 @@ index 91d7d90c47da..94107bf62251 100644 dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); if (!dd) { ret = -ENOMEM; -@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) +@@ -652,6 +658,12 @@ static int acpi_tad_probe(struct platform_device *pdev) if (ret) goto fail; From dfad7a8872530f6b00a38891f29c76ce1a2eda4d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Dec 2025 22:54:21 +0100 Subject: [PATCH 144/236] Update Debian kernel to v6.17.13 --- pkg/debian/kernel/version.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 309a4f492c..653f27adc2 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.17.1" -KERNEL_REVISION="2" +KERNEL_VERSION="6.17.13" +KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 7e38406038fc51b5b2f4d3d51aa9a8504bc2d248 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Dec 2025 23:01:08 +0100 Subject: [PATCH 145/236] Update Arch kernel to v6.17.9 --- pkg/arch/kernel/PKGBUILD | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 11405fc4e1..6f3528f9b4 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.17.1.arch1 +pkgver=6.17.9.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -63,25 +63,25 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('647162133ecdbf0b829c8291d41a325ce32df79ad93d89302106773a0cac3c87' +sha256sums=('96b647bf9499b9378acd66b174f1d97078cb26a38029545041a443998fe026de' '57786a01f3cfaeb696f79bf3b19996f7f787df3df8c6fbf6a9654aced518ec93' 'ee110be98c41a45302b2b81b037e3c4392ea7f142282e28400ac67b37455d42a' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '04ad5ce818a39165235d387d428aeb12605be8c5b1e913a0c7a12c9c5edef1c2' - '42f639c52f38defda3d5516859c1afc42aa3c162f8f8eb1cbae3677e2a41695f' - '3640e5db83140bb62e2183c69cc00bc00fbf22a1d96479481a2b65486f381218' - '83c63f25996736426892affda4f75f11dd5d176afa39ee7c52d19c109d9b6e97' - '4f0833e207090cef3dc8af42c28e42f91138a5fbbd52b3a21dfcde435fe5d352' - '7fda97124a4bbd20077617c9ebd27f550159a82de68c488c689efb19b7dd42ae' - '2ce4ddf8715ba5c406ba1143b2082268b6b3ba297b694944c826765340783afe' - '79a81118886c06aa35a9963ce39d97bf996cdfae2d35089ba3075c1e7fd2d9b3' - '172a6b04b90885f0edd7609b287a534061c639a746c3b7eaf1994df81e7e9084' - '43c82fbb7583be29d2e49447e7ee1860745d5cfe2af3fd1439aacbe4aee84522' - '10756fbb38b21e4c886826c29b042028a42d42cc064178a53a8389b3945cadf9' - '8ef4848edcfd3a284e9a69d297b303023dda27b8482cbd5d7f67a8e59082da1c' - '4e893decdb56341e542bc4aed20c9507670e4a68b732cc638bd93ad2ef18b16b' - 'e46a3593f44b32eb8ef9295412e912716a676eb42d066a65d643ac6b3d6b7ce4' - '5660ab754f3ce5ac0a0af746b93b573322f9e940a8ab6f0890aae2e38a86e181') + 'b226336b2817ad3d6f657bfc0d3156d4c827839254959a64e326ad3874f998bf' + '3618b7046cdf9b396b64d00fd8520498ed7d57e1910e020a127ca455837c9ec5' + '8b40cd801a9f440a5290aeb01df47470901cc2134efb04a4264ba404ddd45d57' + '9c3eacb2b12cef6c05dcdc7d2ff0ab18143e087819223494835bdf84afb78b5f' + '99b1118e0949422826a5c74ffb764040c8c36e5bb3a5cc86b688da8e600b260e' + '5c42ed2768cd2c3b905ef074eed0dd42b8784bbad1b9f30954932862a6b03641' + '8ef25afa0e0eb3c3db7105664952b2a24b6eabff0b93fa09f634c556dfec49b1' + 'f86649692c36bcd817920794dd28c287eaa673a885ebd6dbd5c6a0e31a243be9' + '490ac2b0c7a2ce95fa6f764cd7e727685b51fe1c06e528fe6ffb2989e53b22d2' + 'a60fa1d25b71f6b94fdb8a6b7f8935d79fa6c4fcf347c403b3f3f2ab8755eb6a' + '4c9771739d67d5704818405390acadb09882433e185837db5f3ca71c86d4c1f3' + '9c9633bf05c7198f0076dfbdc68007c594d5b22f91615920a60a0dd2f1eac5d9' + 'ed39543bd42481cf4ca3374e51380671bb2f28d1a860269b4324147b56fbeeba' + '09c7435d1a0069d17adf037a881f6765a7717e9fe82c5c2fa3d8bb6e09405410' + 'c382fa5be5966efefaa90bbf0e49f2a5a43e62ec4556defbd4fb48d2bc09ea21') export KBUILD_BUILD_HOST=archlinux From 36eab7200e0d121973c76a35bafacfa4183399d8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Dec 2025 23:02:43 +0100 Subject: [PATCH 146/236] Update Fedora kernels to v6.17.13 --- .../kernel-surface/build-linux-surface.py | 2 +- ...1-Pull-in-iptsd-as-a-weak-dependency.patch | 4 +- ...ce-provide-the-standard-package-name.patch | 4 +- ...ce-conflict-with-older-versions-of-t.patch | 4 +- ...and-service-files-for-keeping-the-su.patch | 4 +- .../0005-Pull-in-intel-vsc-firmware.patch | 4 +- .../patches/0006-Drop-riscv64-configs.patch | 86 +++++++++++++++++++ 7 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 pkg/fedora/kernel-surface/patches/0006-Drop-riscv64-configs.patch diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index d2667535c4..d413ee54c0 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.16.11-0" +PACKAGE_TAG = "kernel-6.17.13-0" ## ## The release number of the modified kernel package. diff --git a/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch index 69507ef889..be10be8f3d 100644 --- a/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch +++ b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch @@ -1,7 +1,7 @@ -From 85bd89ed2f2310e99a0c4f291e02dcba08383570 Mon Sep 17 00:00:00 2001 +From 5747933cc59471903b75a640b7adc3ee152cb92f Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:33:03 +0200 -Subject: [PATCH 1/5] Pull in iptsd as a weak dependency +Subject: [PATCH 1/6] Pull in iptsd as a weak dependency Signed-off-by: Dorian Stoll --- diff --git a/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch index 3db31957fd..d97e8f47fb 100644 --- a/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch +++ b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch @@ -1,7 +1,7 @@ -From 33d5f8140694dd1c6e033fbf310c7c7785f07c90 Mon Sep 17 00:00:00 2001 +From 3a68edfb0846e4fea4a947cb70bf3c2eb181ad47 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:09:20 +0200 -Subject: [PATCH 2/5] Let kernel-surface provide the standard package names +Subject: [PATCH 2/6] Let kernel-surface provide the standard package names Signed-off-by: Dorian Stoll --- diff --git a/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch index bf496ffea1..7f5234cd94 100644 --- a/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch +++ b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch @@ -1,7 +1,7 @@ -From 9cfe9cb267c9ba855738b6474c22f95ac4445b07 Mon Sep 17 00:00:00 2001 +From e36d14a3c95845d54befe766b15a89d9ca65e1ef Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:10:38 +0200 -Subject: [PATCH 3/5] Let kernel-surface conflict with older versions of the +Subject: [PATCH 3/6] Let kernel-surface conflict with older versions of the package Signed-off-by: Dorian Stoll diff --git a/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch index 816e0d500a..f85919bc53 100644 --- a/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch +++ b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch @@ -1,7 +1,7 @@ -From 2a2842c01b07268627d47ef2f12377a19a34e093 Mon Sep 17 00:00:00 2001 +From f7f864a34eb97847097e2250129a8b04dfeb8bff Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:12:29 +0200 -Subject: [PATCH 4/5] Install scripts and service files for keeping the surface +Subject: [PATCH 4/6] Install scripts and service files for keeping the surface kernel the default Signed-off-by: Dorian Stoll diff --git a/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch index dcb561e324..53c5de73ac 100644 --- a/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch +++ b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch @@ -1,7 +1,7 @@ -From 8f14c27edbb29fdc927168d41174dc5a4b9f80db Mon Sep 17 00:00:00 2001 +From 86059570fd818aeb68dc7caf725a996e3183d0e1 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:14:00 +0200 -Subject: [PATCH 5/5] Pull in intel-vsc-firmware +Subject: [PATCH 5/6] Pull in intel-vsc-firmware This package contains the IPU3 firmware needed for camera support. --- diff --git a/pkg/fedora/kernel-surface/patches/0006-Drop-riscv64-configs.patch b/pkg/fedora/kernel-surface/patches/0006-Drop-riscv64-configs.patch new file mode 100644 index 0000000000..103d7ef4bf --- /dev/null +++ b/pkg/fedora/kernel-surface/patches/0006-Drop-riscv64-configs.patch @@ -0,0 +1,86 @@ +From ded050bca1992e57147e86986acbf2a6c46fd91c Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Tue, 30 Dec 2025 23:42:38 +0100 +Subject: [PATCH 6/6] Drop riscv64 configs + +Those seem to make some problems... so drop them for now. +--- + redhat/configs/priority.common | 4 ---- + redhat/configs/priority.fedora | 6 ------ + redhat/configs/priority.rhel | 4 ---- + redhat/kernel.spec.template | 7 ------- + 4 files changed, 21 deletions(-) + +diff --git a/redhat/configs/priority.common b/redhat/configs/priority.common +index ea4b1122b1a1..cb1f09840cff 100644 +--- a/redhat/configs/priority.common ++++ b/redhat/configs/priority.common +@@ -19,7 +19,3 @@ aarch64=generic:generic-arm:generic-arm-aarch64 + aarch64-debug=generic:generic-arm:generic-arm-aarch64:debug:debug-arm-aarch64 + aarch64-16k-debug=generic:generic-arm:generic-arm-aarch64:generic-arm-aarch64-16k:debug:debug-arm-aarch64:debug-arm-aarch64-16k + aarch64-64k-debug=generic:generic-arm:generic-arm-aarch64:generic-arm-aarch64-64k:debug:debug-arm-aarch64:debug-arm-aarch64-64k +- +-# riscv64 +-riscv64=generic:generic-riscv:generic-riscv-riscv64 +-riscv64-debug=generic:generic-riscv:generic-riscv-riscv64:debug:debug-riscv-riscv64 +diff --git a/redhat/configs/priority.fedora b/redhat/configs/priority.fedora +index e72726642039..658970a57293 100644 +--- a/redhat/configs/priority.fedora ++++ b/redhat/configs/priority.fedora +@@ -42,9 +42,3 @@ aarch64-rt=generic:generic-arm:generic-arm-aarch64:rt-generic:rt-generic-arm:rt- + aarch64-rt-debug=generic:generic-arm:generic-arm-aarch64:debug:debug-arm:debug-arm-aarch64:rt-generic:rt-generic-arm:rt-generic-arm-aarch64:rt-debug:rt-debug-arm:rt-debug-arm-aarch64 + aarch64-rt-64k=generic:generic-arm:generic-arm-aarch64:rt-generic:rt-arm-aarch64:rt-arm-aarch64-64k + aarch64-rt-64k-debug=generic:generic-arm:generic-arm-aarch64:rt-generic:rt-arm-aarch64:rt-arm-aarch64-64k:debug:debug-arm-aarch64:rt-debug +- +-# riscv64 +-riscv64=generic:generic-riscv:generic-riscv-riscv64 +-riscv64-debug=generic:generic-riscv:generic-riscv-riscv64:debug:debug-riscv-riscv64 +-riscv64-rt=generic:generic-riscv:generic-riscv-riscv64:rt-generic:rt-generic-riscv-riscv64 +-riscv64-rt-debug=generic:generic-riscv:generic-riscv-riscv64:debug:debug-riscv-riscv64:rt-generic:rt-generic-riscv-riscv64:rt-debug:rt-debug-riscv-riscv64 +diff --git a/redhat/configs/priority.rhel b/redhat/configs/priority.rhel +index 2f739fc47f31..4e56dcad5f76 100644 +--- a/redhat/configs/priority.rhel ++++ b/redhat/configs/priority.rhel +@@ -46,7 +46,3 @@ aarch64-rt-64k=generic:generic-arm:generic-arm-aarch64:rt-generic:rt-arm-aarch64 + aarch64-rt-64k-debug=generic:generic-arm:generic-arm-aarch64:rt-generic:rt-arm-aarch64:rt-arm-aarch64-64k:debug:debug-arm-aarch64:rt-debug + aarch64-automotive=generic:generic-arm:generic-arm-aarch64:rt-generic:rt-generic-arm:rt-generic-arm-aarch64:automotive-generic:automotive-generic-arm:automotive-generic-arm-aarch64 + aarch64-automotive-debug=generic:generic-arm:generic-arm-aarch64:debug:debug-arm:debug-arm-aarch64:rt-generic:rt-generic-arm:rt-generic-arm-aarch64:rt-debug:rt-debug-arm:rt-debug-arm-aarch64:automotive-generic:automotive-generic-arm:automotive-generic-arm-aarch64:automotive-debug:automotive-debug-arm:automotive-debug-arm-aarch64 +- +-# riscv64 +-riscv64=generic:generic-riscv:generic-riscv-riscv64 +-riscv64-debug=generic:generic-riscv:generic-riscv-riscv64:debug:debug-riscv-riscv64 +diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template +index 79e67a8b1440..be4e401212b5 100644 +--- a/redhat/kernel.spec.template ++++ b/redhat/kernel.spec.template +@@ -1015,9 +1015,6 @@ Source33: %{name}-x86_64-debug-rhel.config + # ARM64 64K page-size kernel config + Source42: %{name}-aarch64-64k-rhel.config + Source43: %{name}-aarch64-64k-debug-rhel.config +- +-Source44: %{name}-riscv64-rhel.config +-Source45: %{name}-riscv64-debug-rhel.config + %endif + + %if %{include_rhel} || %{include_automotive} +@@ -1039,8 +1036,6 @@ Source58: %{name}-s390x-fedora.config + Source59: %{name}-s390x-debug-fedora.config + Source60: %{name}-x86_64-fedora.config + Source61: %{name}-x86_64-debug-fedora.config +-Source700: %{name}-riscv64-fedora.config +-Source701: %{name}-riscv64-debug-fedora.config + + Source62: def_variants.yaml.fedora + %endif +@@ -1125,8 +1120,6 @@ Source482: %{name}-aarch64-rt-64k-fedora.config + Source483: %{name}-aarch64-rt-64k-debug-fedora.config + Source484: %{name}-x86_64-rt-fedora.config + Source485: %{name}-x86_64-rt-debug-fedora.config +-Source486: %{name}-riscv64-rt-fedora.config +-Source487: %{name}-riscv64-rt-debug-fedora.config + %endif + %endif + +-- +2.52.0 + From ef890694c0336f842ebf9bb5a581fef320d93734 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 01:16:54 +0100 Subject: [PATCH 147/236] Update v6.17 patches Changes: - Include Surface Pro 9 camera patch - Rename hid-surface patch --- patches/6.17/0001-secureboot.patch | 4 +- patches/6.17/0002-surface3.patch | 4 +- patches/6.17/0003-mwifiex.patch | 6 +- patches/6.17/0004-ath10k.patch | 2 +- patches/6.17/0005-ipts.patch | 6 +- patches/6.17/0006-ithc.patch | 4 +- patches/6.17/0007-surface-sam.patch | 4 +- patches/6.17/0008-surface-sam-over-hid.patch | 4 +- patches/6.17/0009-surface-button.patch | 4 +- patches/6.17/0010-surface-typecover.patch | 6 +- patches/6.17/0011-surface-shutdown.patch | 2 +- patches/6.17/0012-surface-gpe.patch | 2 +- patches/6.17/0013-cameras.patch | 374 +++++++++++++++++- patches/6.17/0014-amd-gpio.patch | 8 +- patches/6.17/0015-rtc.patch | 4 +- ...ce-fn-key.patch => 0016-hid-surface.patch} | 9 +- .../surface-pro9-camera-support.patch | 333 ---------------- 17 files changed, 400 insertions(+), 376 deletions(-) rename patches/6.17/{0016-hid-surface-fn-key.patch => 0016-hid-surface.patch} (96%) delete mode 100644 patches/experimental/surface-pro9-camera-support.patch diff --git a/patches/6.17/0001-secureboot.patch b/patches/6.17/0001-secureboot.patch index 5a7324937c..e385f0afa1 100644 --- a/patches/6.17/0001-secureboot.patch +++ b/patches/6.17/0001-secureboot.patch @@ -33,7 +33,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.51.0 +2.52.0 From 7678fd13a6f86c4f58b733a79e8bf5396133b70b Mon Sep 17 00:00:00 2001 From: "J. Eduardo" @@ -108,5 +108,5 @@ index 53166ef86ba4..5b33262b17b5 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0002-surface3.patch b/patches/6.17/0002-surface3.patch index 1279854d8c..e24592c57e 100644 --- a/patches/6.17/0002-surface3.patch +++ b/patches/6.17/0002-surface3.patch @@ -97,7 +97,7 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.51.0 +2.52.0 From 9bfd71c1927f31059a4edef27a0eaf8e507a28d0 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> @@ -230,5 +230,5 @@ index 6074b7730e86..6aa3e1d6f160 100644 } -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0003-mwifiex.patch b/patches/6.17/0003-mwifiex.patch index bda22d5841..bb00e40a2e 100644 --- a/patches/6.17/0003-mwifiex.patch +++ b/patches/6.17/0003-mwifiex.patch @@ -163,7 +163,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.51.0 +2.52.0 From 49f5c1a53f5679011fc7f135a38593393fa8d3fb Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto @@ -318,7 +318,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.51.0 +2.52.0 From 23dc291355b16ee49055464ea4d8bd4095058988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= @@ -396,5 +396,5 @@ index fa683bb7f0b4..f80e194aa970 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0004-ath10k.patch b/patches/6.17/0004-ath10k.patch index 9ffa08b237..2895e8e9b8 100644 --- a/patches/6.17/0004-ath10k.patch +++ b/patches/6.17/0004-ath10k.patch @@ -116,5 +116,5 @@ index 9ae3595fb698..b26a39c97998 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0005-ipts.patch b/patches/6.17/0005-ipts.patch index be7f508306..4a77be85cd 100644 --- a/patches/6.17/0005-ipts.patch +++ b/patches/6.17/0005-ipts.patch @@ -35,7 +35,7 @@ index bc0fc584a8e4..51a91ef66cda 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.51.0 +2.52.0 From dc61b222997c8a6d8b8753cbcb91c1373b31f227 Mon Sep 17 00:00:00 2001 From: Liban Hannan @@ -142,7 +142,7 @@ index e236c7ec221f..9e31a5fe1f66 100644 { if (risky_device(dev)) -- -2.51.0 +2.52.0 From 841a09e0a458128d888a94118983406352f94256 Mon Sep 17 00:00:00 2001 From: Dorian Stoll @@ -3239,5 +3239,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0006-ithc.patch b/patches/6.17/0006-ithc.patch index 1c069e771b..39c4a5a4cf 100644 --- a/patches/6.17/0006-ithc.patch +++ b/patches/6.17/0006-ithc.patch @@ -37,7 +37,7 @@ index 4f9b01dc91e8..e4d73e45473c 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.51.0 +2.52.0 From 76846a0bd73bdd9331670be1f5006f2913500e7e Mon Sep 17 00:00:00 2001 From: quo @@ -2776,5 +2776,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0007-surface-sam.patch b/patches/6.17/0007-surface-sam.patch index cd60cc0641..53964c52a1 100644 --- a/patches/6.17/0007-surface-sam.patch +++ b/patches/6.17/0007-surface-sam.patch @@ -179,7 +179,7 @@ index 000000000000..f6c17c4e98d5 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.51.0 +2.52.0 From 9cbed80f9cd071c2ffdd63590cf0d232612877dc Mon Sep 17 00:00:00 2001 From: Maximilian Luz @@ -207,5 +207,5 @@ index a594d5fcfcfd..07b03aa4fa7f 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0008-surface-sam-over-hid.patch b/patches/6.17/0008-surface-sam-over-hid.patch index 99e3b23c41..c02363c3f4 100644 --- a/patches/6.17/0008-surface-sam-over-hid.patch +++ b/patches/6.17/0008-surface-sam-over-hid.patch @@ -107,7 +107,7 @@ index ed90858a27b7..070c36637811 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.51.0 +2.52.0 From 1d7ce37d06481d6c9ce1c019788a64b86cf946b4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0009-surface-button.patch b/patches/6.17/0009-surface-button.patch index 76d2adb6ed..b3f58f8d9d 100644 --- a/patches/6.17/0009-surface-button.patch +++ b/patches/6.17/0009-surface-button.patch @@ -73,7 +73,7 @@ index b8cad415c62c..43b5d56383e3 100644 /* -- -2.51.0 +2.52.0 From ccc1fc9362ec228d5821d9c5578eeaa90d9db42b Mon Sep 17 00:00:00 2001 From: Sachi King @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0010-surface-typecover.patch b/patches/6.17/0010-surface-typecover.patch index f0719ba14b..079d9b39db 100644 --- a/patches/6.17/0010-surface-typecover.patch +++ b/patches/6.17/0010-surface-typecover.patch @@ -37,7 +37,7 @@ index 47f589c4104a..6b00aec67ee2 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.51.0 +2.52.0 From d5768e0e9b7b9fe1274170b6c4e2a62e508a2f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= @@ -272,7 +272,7 @@ index a9ff84f0bd9b..1b2fc88ce1cf 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.51.0 +2.52.0 From 9ab3ab41c4292e3877f81a960147521b9c29a935 Mon Sep 17 00:00:00 2001 From: PJungkamp @@ -571,5 +571,5 @@ index 1b2fc88ce1cf..dd200064e309 100644 unregister_pm_notifier(&td->pm_notifier); timer_delete_sync(&td->release_timer); -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0011-surface-shutdown.patch b/patches/6.17/0011-surface-shutdown.patch index 6554315a1a..b837c4fb48 100644 --- a/patches/6.17/0011-surface-shutdown.patch +++ b/patches/6.17/0011-surface-shutdown.patch @@ -93,5 +93,5 @@ index 7735acf6f349..27780b0f1115 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0012-surface-gpe.patch b/patches/6.17/0012-surface-gpe.patch index a9c5f65a86..f1c02814e3 100644 --- a/patches/6.17/0012-surface-gpe.patch +++ b/patches/6.17/0012-surface-gpe.patch @@ -47,5 +47,5 @@ index b359413903b1..b4496db79f39 100644 .ident = "Surface Book 1", .matches = { -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0013-cameras.patch b/patches/6.17/0013-cameras.patch index e5300bbe72..2ef4d7ed4a 100644 --- a/patches/6.17/0013-cameras.patch +++ b/patches/6.17/0013-cameras.patch @@ -72,7 +72,7 @@ index f2e032f38162..c45820be8fd0 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.51.0 +2.52.0 From c552e13ba9c4e725c8ab68016affe3697a7102d5 Mon Sep 17 00:00:00 2001 From: zouxiaoh @@ -182,7 +182,7 @@ index 9e31a5fe1f66..bdd32551c452 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.51.0 +2.52.0 From 9868645027474ea4be300614971df7bf4fbe0e4a Mon Sep 17 00:00:00 2001 From: Daniel Scally @@ -219,7 +219,7 @@ index 0133405697dc..9e0763bdc758 100644 return 0; -- -2.51.0 +2.52.0 From add99db7db117172d47c6a3feb318cb83ab7b535 Mon Sep 17 00:00:00 2001 From: Daniel Scally @@ -258,7 +258,7 @@ index 31a42d81e970..0d5a8fd86e67 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.51.0 +2.52.0 From 4983fa30433b34386e8d43e72e348a00b3d0ef9d Mon Sep 17 00:00:00 2001 From: Daniel Scally @@ -309,7 +309,7 @@ index cb153ce42c45..f11b499e14bb 100644 if (ret < 0) goto out_cleanup; -- -2.51.0 +2.52.0 From 6a40dbaaa72f332b416a2722b93d22f4e7341ad7 Mon Sep 17 00:00:00 2001 From: Kate Hsuan @@ -350,7 +350,7 @@ index 9e0763bdc758..0976b267972b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.51.0 +2.52.0 From 501f49d48266ee52109f35a50c7a63a7190d5bff Mon Sep 17 00:00:00 2001 From: Kate Hsuan @@ -391,7 +391,7 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.51.0 +2.52.0 From 93f9dbec991c78763d0abdf567539691b9ef3cab Mon Sep 17 00:00:00 2001 From: Kate Hsuan @@ -642,7 +642,7 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.51.0 +2.52.0 From 82a0860d4f7b8226e21577a3956f620d3bbca6c2 Mon Sep 17 00:00:00 2001 From: mojyack @@ -674,5 +674,361 @@ index 032fbcb981f2..e03a1d8cdcb4 100644 cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); fsleep(100); -- -2.51.0 +2.52.0 + +From df7085a9fcdd1e8c2cf71fa555c2b63f13ae7d66 Mon Sep 17 00:00:00 2001 +From: Tooraj Taraz +Date: Wed, 31 Dec 2025 00:35:50 +0100 +Subject: [PATCH] Add camera support for Surface Pro 9 + +Experimental camera support for the Surface Pro 9. + +Link: https://github.com/linux-surface/linux-surface/pull/1867 +Patchset: cameras +--- + drivers/media/i2c/ov13858.c | 166 +++++++++++++++++- + drivers/media/i2c/ov5693.c | 1 + + drivers/media/pci/intel/ipu-bridge.c | 4 + + drivers/platform/x86/intel/int3472/discrete.c | 23 +++ + 4 files changed, 190 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c +index 7a3fc1d28514..970b224cb466 100644 +--- a/drivers/media/i2c/ov13858.c ++++ b/drivers/media/i2c/ov13858.c +@@ -2,6 +2,8 @@ + // Copyright (c) 2017 Intel Corporation. + + #include ++#include ++#include + #include + #include + #include +@@ -118,6 +120,14 @@ struct ov13858_mode { + struct ov13858_reg_list reg_list; + }; + ++// Or use standard names that might be more correct: ++static const char * const ov13858_supply_names[] = { ++ "avdd", // Analog voltage ++ "pwr1", // Digital core voltage ++}; ++ ++#define OV13858_NUM_SUPPLIES ARRAY_SIZE(ov13858_supply_names) ++ + /* 4224x3136 needs 1080Mbps/lane, 4 lanes */ + static const struct ov13858_reg mipi_data_rate_1080mbps[] = { + /* PLL1 registers */ +@@ -1041,13 +1051,131 @@ struct ov13858 { + + /* Current mode */ + const struct ov13858_mode *cur_mode; +- ++ struct regulator_bulk_data supplies[OV13858_NUM_SUPPLIES]; ++ struct gpio_desc *reset; ++ struct clk *xvclk; + /* Mutex for serialized access */ + struct mutex mutex; + }; + + #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) + ++ ++static int ov13858_get_regulators(struct ov13858 *ov13858) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); ++ unsigned int i; ++ ++ for (i = 0; i < OV13858_NUM_SUPPLIES; i++) ++ ov13858->supplies[i].supply = ov13858_supply_names[i]; ++ ++ return devm_regulator_bulk_get(&client->dev, OV13858_NUM_SUPPLIES, ++ ov13858->supplies); ++} ++ ++static int ov13858_sensor_powerup(struct ov13858 *ov13858) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); ++ int ret; ++ ++ dev_info(&client->dev, "Powering up sensor\n"); ++ ++ /* Assert reset */ ++ gpiod_set_value_cansleep(ov13858->reset, 1); ++ ++ /* Enable clock FIRST - sensor needs clock to communicate */ ++ ret = clk_prepare_enable(ov13858->xvclk); ++ if (ret) { ++ dev_err(&client->dev, "Failed to enable clock: %d\n", ret); ++ return ret; ++ } ++ dev_info(&client->dev, "Clock enabled\n"); ++ ++ /* Enable regulators */ ++ ret = regulator_bulk_enable(OV13858_NUM_SUPPLIES, ov13858->supplies); ++ if (ret) { ++ dev_err(&client->dev, "Failed to enable regulators: %d\n", ret); ++ clk_disable_unprepare(ov13858->xvclk); ++ return ret; ++ } ++ ++ dev_info(&client->dev, "Regulators enabled\n"); ++ ++ /* Wait for power to stabilize */ ++ usleep_range(5000, 10000); ++ ++ /* De-assert reset */ ++ gpiod_set_value_cansleep(ov13858->reset, 0); ++ ++ /* Wait for sensor to boot */ ++ msleep(20); ++ ++ dev_info(&client->dev, "Reset de-asserted, sensor should be ready\n"); ++ ++ return 0; ++} ++ ++static void ov13858_sensor_powerdown(struct ov13858 *ov13858) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); ++ ++ dev_info(&client->dev, "Powering down sensor\n"); ++ ++ /* Assert reset to put sensor in reset state */ ++ gpiod_set_value_cansleep(ov13858->reset, 1); ++ ++ /* Disable regulators */ ++ regulator_bulk_disable(OV13858_NUM_SUPPLIES, ov13858->supplies); ++ dev_info(&client->dev, "Regulators disabled\n"); ++ ++ /* Disable clock */ ++ clk_disable_unprepare(ov13858->xvclk); ++ dev_info(&client->dev, "Clock disabled\n"); ++} ++ ++static int __maybe_unused ov13858_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov13858 *ov13858 = to_ov13858(sd); ++ ++ ov13858_sensor_powerdown(ov13858); ++ ++ return 0; ++} ++ ++static int __maybe_unused ov13858_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov13858 *ov13858 = to_ov13858(sd); ++ int ret; ++ ++ ret = ov13858_sensor_powerup(ov13858); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ov13858_pm_ops = { ++ SET_RUNTIME_PM_OPS(ov13858_suspend, ov13858_resume, NULL) ++}; ++ ++static int ov13858_get_gpios(struct ov13858 *ov13858) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); ++ ++ ov13858->reset = devm_gpiod_get_optional(&client->dev, "reset", ++ GPIOD_OUT_HIGH); ++ if (IS_ERR(ov13858->reset)) { ++ dev_err(&client->dev, "Error fetching reset GPIO\n"); ++ return PTR_ERR(ov13858->reset); ++ } ++ ++ return 0; ++} ++ + /* Read registers up to 4 at a time */ + static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, + u32 *val) +@@ -1499,8 +1627,11 @@ static int ov13858_identify_module(struct ov13858 *ov13858) + int ret; + u32 val; + ++ dev_info(&client->dev, "Attempting to read chip ID from register 0x300a\n"); + ret = ov13858_read_reg(ov13858, OV13858_REG_CHIP_ID, + OV13858_REG_VALUE_24BIT, &val); ++ dev_info(&client->dev, "Chip ID read result: ret=%d, val=0x%06x (expected 0x%06x)\n", ++ ret, val, OV13858_CHIP_ID); + if (ret) + return ret; + +@@ -1509,7 +1640,7 @@ static int ov13858_identify_module(struct ov13858 *ov13858) + OV13858_CHIP_ID, val); + return -EIO; + } +- ++ dev_info(&client->dev, "Chip ID verified successfully!\n"); + return 0; + } + +@@ -1664,6 +1795,7 @@ static int ov13858_probe(struct i2c_client *client) + u32 val = 0; + + device_property_read_u32(&client->dev, "clock-frequency", &val); ++ dev_info(&client->dev, "Clock frequency read: %u (expected 19200000)\n", val); + if (val != 19200000) + return -EINVAL; + +@@ -1671,14 +1803,33 @@ static int ov13858_probe(struct i2c_client *client) + if (!ov13858) + return -ENOMEM; + ++ /* Get the external clock */ ++ ov13858->xvclk = devm_clk_get_optional(&client->dev, "xvclk"); ++ if (IS_ERR(ov13858->xvclk)) ++ return dev_err_probe(&client->dev, PTR_ERR(ov13858->xvclk), ++ "failed to get xvclk\n"); ++ + /* Initialize subdev */ + v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops); + ++ ret = ov13858_get_regulators(ov13858); ++ if (ret) ++ return dev_err_probe(&client->dev, ret, ++ "Error fetching regulators\n"); ++ ++ ret = ov13858_get_gpios(ov13858); ++ if (ret) ++ return ret; ++ ++ ret = ov13858_sensor_powerup(ov13858); ++ if (ret) ++ return ret; // No cleanup needed yet, devm handles GPIOs/regulators ++ + /* Check module identity */ + ret = ov13858_identify_module(ov13858); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d\n", ret); +- return ret; ++ goto error_power_off; // Now we need to power down + } + + /* Set default mode to max resolution */ +@@ -1686,7 +1837,7 @@ static int ov13858_probe(struct i2c_client *client) + + ret = ov13858_init_controls(ov13858); + if (ret) +- return ret; ++ goto error_power_off; + + /* Initialize subdev */ + ov13858->sd.internal_ops = &ov13858_internal_ops; +@@ -1722,6 +1873,9 @@ static int ov13858_probe(struct i2c_client *client) + + error_handler_free: + ov13858_free_controls(ov13858); ++ ++error_power_off: ++ ov13858_sensor_powerdown(ov13858); + dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + + return ret; +@@ -1737,6 +1891,9 @@ static void ov13858_remove(struct i2c_client *client) + ov13858_free_controls(ov13858); + + pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ ov13858_sensor_powerdown(ov13858); ++ pm_runtime_set_suspended(&client->dev); + } + + static const struct i2c_device_id ov13858_id_table[] = { +@@ -1758,6 +1915,7 @@ MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids); + static struct i2c_driver ov13858_i2c_driver = { + .driver = { + .name = "ov13858", ++ .pm = &ov13858_pm_ops, + .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), + }, + .probe = ov13858_probe, +diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c +index 485efd15257e..476efd022f6b 100644 +--- a/drivers/media/i2c/ov5693.c ++++ b/drivers/media/i2c/ov5693.c +@@ -1408,6 +1408,7 @@ static const struct dev_pm_ops ov5693_pm_ops = { + + static const struct acpi_device_id ov5693_acpi_match[] = { + {"INT33BE"}, ++ {"OVTI5693"}, + {}, + }; + MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +index 4e579352ab2c..ac637207b644 100644 +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -60,6 +60,10 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { + IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), + /* Onsemi MT9M114 */ + IPU_SENSOR_CONFIG("INT33F0", 1, 384000000), ++ /* Omnivision OV5693 - Surface Pro 9 */ ++ IPU_SENSOR_CONFIG("OVTI5693", 1, 419200000), ++ /* Omnivision OV13858 - Surface Pro 9 */ ++ IPU_SENSOR_CONFIG("OVTID858", 4, 540000000), + /* Omnivision OV2740 */ + IPU_SENSOR_CONFIG("INT3474", 1, 180000000), + /* Omnivision OV5670 */ +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index bdfb8a800c54..b559112ee763 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -205,6 +205,14 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 + *con_id = "dvdd"; + *gpio_flags = GPIO_ACTIVE_HIGH; + break; ++ case 0x08: /* Surface Pro 9 - additional power rail */ ++ *con_id = "pwr1"; ++ *gpio_flags = GPIO_ACTIVE_HIGH; ++ break; ++ case 0x10: /* Surface Pro 9 - secondary power rail */ ++ *con_id = "pwr2"; ++ *gpio_flags = GPIO_ACTIVE_HIGH; ++ break; + default: + *con_id = "unknown"; + *gpio_flags = GPIO_ACTIVE_HIGH; +@@ -307,6 +315,8 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, + case INT3472_GPIO_TYPE_PRIVACY_LED: + case INT3472_GPIO_TYPE_POWER_ENABLE: + case INT3472_GPIO_TYPE_HANDSHAKE: ++ case 0x08: /* Surface Pro 9 power rails */ ++ case 0x10: + gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); + if (IS_ERR(gpio)) { + ret = PTR_ERR(gpio); +@@ -345,6 +355,19 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, + err_msg = "Failed to map handshake to sensor\n"; + + break; ++ case 0x08: /* Surface Pro 9 - treat as power*/ ++ dev_info(int3472->dev, "GPIO type 0x%02x detected on pin 0x%02x\n", type, agpio->pin_table[0]); ++ dev_info(int3472->dev, " con_id=%s, flags=0x%x\n", con_id, gpio_flags); ++ ret = skl_int3472_register_regulator(int3472, gpio, ++ GPIO_REGULATOR_ENABLE_TIME, ++ con_id, NULL); ++ dev_info(int3472->dev, " register_regulator returned: %d\n", ret); ++ if (ret) { ++ dev_err(int3472->dev, "Failed to register type 0x02x: %d\n", type, ret); ++ } ++ break; ++ case 0x10: ++ break; + default: /* Never reached */ + ret = -EINVAL; + break; +-- +2.52.0 diff --git a/patches/6.17/0014-amd-gpio.patch b/patches/6.17/0014-amd-gpio.patch index 7eb3046197..1b87fe1ece 100644 --- a/patches/6.17/0014-amd-gpio.patch +++ b/patches/6.17/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 87bbb9dd149bc1a198f5ceddf87f4f5da21d7525 Mon Sep 17 00:00:00 2001 +From faea5ffa744ffdce8341423e78d1514a30360026 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 9fa321a95eb3..8914a922be2b 100644 mp_config_acpi_legacy_irqs(); -- -2.51.0 +2.52.0 -From 394d72f5f5dd648258ade2875c2f066aa60cb2e7 Mon Sep 17 00:00:00 2001 +From 46545b3ec777de08bed3ef45022f09fe2029d56c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 8914a922be2b..c43d0a553867 100644 }; -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0015-rtc.patch b/patches/6.17/0015-rtc.patch index 630f56f6c4..1bb2ea06c9 100644 --- a/patches/6.17/0015-rtc.patch +++ b/patches/6.17/0015-rtc.patch @@ -1,4 +1,4 @@ -From c622f89197367a28d3fd8f456dcf36621f5c1ac0 Mon Sep 17 00:00:00 2001 +From a448236a43eec025f3af8967e2a54e91248e708d Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index 33418dd6768a..f94bbdc1de06 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.51.0 +2.52.0 diff --git a/patches/6.17/0016-hid-surface-fn-key.patch b/patches/6.17/0016-hid-surface.patch similarity index 96% rename from patches/6.17/0016-hid-surface-fn-key.patch rename to patches/6.17/0016-hid-surface.patch index fb9cbb61ac..2aec0deaec 100644 --- a/patches/6.17/0016-hid-surface-fn-key.patch +++ b/patches/6.17/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 8ec2ee811c7d8c373f0a012f09f8f1582a6c3cdb Mon Sep 17 00:00:00 2001 +From ee02a87cb3efa966f5168b0bfd0932c474f49ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -18,6 +18,7 @@ Tested on Surface Laptop 4 AMD with KDE Plasma Wayland. After the fix: - Mouse clicks work on all windows Fixes: https://github.com/linux-surface/linux-surface/issues/1851 +Patchset: hid-surface --- drivers/hid/Kconfig | 8 ++++ drivers/hid/Makefile | 1 + @@ -26,10 +27,10 @@ Fixes: https://github.com/linux-surface/linux-surface/issues/1851 create mode 100644 drivers/hid/hid-surface.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index d6bc87be4854..ebb29cd695fe 100644 +index 707983ce6854..9f8cf231d0e2 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1131,6 +1131,14 @@ config HID_SUNPLUS +@@ -1130,6 +1130,14 @@ config HID_SUNPLUS help Support for Sunplus wireless desktop. @@ -153,5 +154,5 @@ index 000000000000..a171ea65672f +MODULE_DESCRIPTION("Microsoft Surface HID driver"); +MODULE_LICENSE("GPL"); -- -2.51.0 +2.52.0 diff --git a/patches/experimental/surface-pro9-camera-support.patch b/patches/experimental/surface-pro9-camera-support.patch deleted file mode 100644 index aaef9e9d00..0000000000 --- a/patches/experimental/surface-pro9-camera-support.patch +++ /dev/null @@ -1,333 +0,0 @@ ---- a/drivers/media/i2c/ov5693.c -+++ b/drivers/media/i2c/ov5693.c -@@ -1403,6 +1403,7 @@ - - static const struct acpi_device_id ov5693_acpi_match[] = { - {"INT33BE"}, -+ {"OVTI5693"}, - {}, - }; - MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); - ---- a/drivers/media/pci/intel/ipu-bridge.c -+++ b/drivers/media/pci/intel/ipu-bridge.c -@@ -58,6 +58,10 @@ - IPU_SENSOR_CONFIG("INT0310", 0), - /* Omnivision OV5693 */ - IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), -+ /* Omnivision OV5693 - Surface Pro 9 */ -+ IPU_SENSOR_CONFIG("OVTI5693", 1, 419200000), -+ /* Omnivision OV13858 - Surface Pro 9 */ -+ IPU_SENSOR_CONFIG("OVTID858", 4, 540000000), - /* Omnivision OV2740 */ - IPU_SENSOR_CONFIG("INT3474", 1, 180000000), - /* Omnivision OV5670 */ - ---- a/drivers/media/i2c/ov13858.c -+++ b/drivers/media/i2c/ov13858.c -@@ -2,6 +2,8 @@ - // Copyright (c) 2017 Intel Corporation. - - #include -+#include -+#include - #include - #include - #include -@@ -118,6 +120,14 @@ - struct ov13858_reg_list reg_list; - }; - -+// Or use standard names that might be more correct: -+static const char * const ov13858_supply_names[] = { -+ "avdd", // Analog voltage -+ "pwr1", // Digital core voltage -+}; -+ -+#define OV13858_NUM_SUPPLIES ARRAY_SIZE(ov13858_supply_names) -+ - /* 4224x3136 needs 1080Mbps/lane, 4 lanes */ - static const struct ov13858_reg mipi_data_rate_1080mbps[] = { - /* PLL1 registers */ -@@ -1041,13 +1051,131 @@ - - /* Current mode */ - const struct ov13858_mode *cur_mode; -- -+ struct regulator_bulk_data supplies[OV13858_NUM_SUPPLIES]; -+ struct gpio_desc *reset; -+ struct clk *xvclk; - /* Mutex for serialized access */ - struct mutex mutex; - }; - - #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) - -+ -+static int ov13858_get_regulators(struct ov13858 *ov13858) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); -+ unsigned int i; -+ -+ for (i = 0; i < OV13858_NUM_SUPPLIES; i++) -+ ov13858->supplies[i].supply = ov13858_supply_names[i]; -+ -+ return devm_regulator_bulk_get(&client->dev, OV13858_NUM_SUPPLIES, -+ ov13858->supplies); -+} -+ -+static int ov13858_sensor_powerup(struct ov13858 *ov13858) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); -+ int ret; -+ -+ dev_info(&client->dev, "Powering up sensor\n"); -+ -+ /* Assert reset */ -+ gpiod_set_value_cansleep(ov13858->reset, 1); -+ -+ /* Enable clock FIRST - sensor needs clock to communicate */ -+ ret = clk_prepare_enable(ov13858->xvclk); -+ if (ret) { -+ dev_err(&client->dev, "Failed to enable clock: %d\n", ret); -+ return ret; -+ } -+ dev_info(&client->dev, "Clock enabled\n"); -+ -+ /* Enable regulators */ -+ ret = regulator_bulk_enable(OV13858_NUM_SUPPLIES, ov13858->supplies); -+ if (ret) { -+ dev_err(&client->dev, "Failed to enable regulators: %d\n", ret); -+ clk_disable_unprepare(ov13858->xvclk); -+ return ret; -+ } -+ -+ dev_info(&client->dev, "Regulators enabled\n"); -+ -+ /* Wait for power to stabilize */ -+ usleep_range(5000, 10000); -+ -+ /* De-assert reset */ -+ gpiod_set_value_cansleep(ov13858->reset, 0); -+ -+ /* Wait for sensor to boot */ -+ msleep(20); -+ -+ dev_info(&client->dev, "Reset de-asserted, sensor should be ready\n"); -+ -+ return 0; -+} -+ -+static void ov13858_sensor_powerdown(struct ov13858 *ov13858) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); -+ -+ dev_info(&client->dev, "Powering down sensor\n"); -+ -+ /* Assert reset to put sensor in reset state */ -+ gpiod_set_value_cansleep(ov13858->reset, 1); -+ -+ /* Disable regulators */ -+ regulator_bulk_disable(OV13858_NUM_SUPPLIES, ov13858->supplies); -+ dev_info(&client->dev, "Regulators disabled\n"); -+ -+ /* Disable clock */ -+ clk_disable_unprepare(ov13858->xvclk); -+ dev_info(&client->dev, "Clock disabled\n"); -+} -+ -+static int __maybe_unused ov13858_suspend(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct ov13858 *ov13858 = to_ov13858(sd); -+ -+ ov13858_sensor_powerdown(ov13858); -+ -+ return 0; -+} -+ -+static int __maybe_unused ov13858_resume(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct ov13858 *ov13858 = to_ov13858(sd); -+ int ret; -+ -+ ret = ov13858_sensor_powerup(ov13858); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops ov13858_pm_ops = { -+ SET_RUNTIME_PM_OPS(ov13858_suspend, ov13858_resume, NULL) -+}; -+ -+static int ov13858_get_gpios(struct ov13858 *ov13858) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); -+ -+ ov13858->reset = devm_gpiod_get_optional(&client->dev, "reset", -+ GPIOD_OUT_HIGH); -+ if (IS_ERR(ov13858->reset)) { -+ dev_err(&client->dev, "Error fetching reset GPIO\n"); -+ return PTR_ERR(ov13858->reset); -+ } -+ -+ return 0; -+} -+ - /* Read registers up to 4 at a time */ - static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, - u32 *val) -@@ -1499,8 +1627,11 @@ - int ret; - u32 val; - -+ dev_info(&client->dev, "Attempting to read chip ID from register 0x300a\n"); - ret = ov13858_read_reg(ov13858, OV13858_REG_CHIP_ID, - OV13858_REG_VALUE_24BIT, &val); -+ dev_info(&client->dev, "Chip ID read result: ret=%d, val=0x%06x (expected 0x%06x)\n", -+ ret, val, OV13858_CHIP_ID); - if (ret) - return ret; - -@@ -1509,7 +1640,7 @@ - OV13858_CHIP_ID, val); - return -EIO; - } -- -+ dev_info(&client->dev, "Chip ID verified successfully!\n"); - return 0; - } - -@@ -1664,6 +1795,7 @@ - u32 val = 0; - - device_property_read_u32(&client->dev, "clock-frequency", &val); -+ dev_info(&client->dev, "Clock frequency read: %u (expected 19200000)\n", val); - if (val != 19200000) - return -EINVAL; - -@@ -1671,14 +1803,33 @@ - if (!ov13858) - return -ENOMEM; - -+ /* Get the external clock */ -+ ov13858->xvclk = devm_clk_get_optional(&client->dev, "xvclk"); -+ if (IS_ERR(ov13858->xvclk)) -+ return dev_err_probe(&client->dev, PTR_ERR(ov13858->xvclk), -+ "failed to get xvclk\n"); -+ - /* Initialize subdev */ - v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops); - -+ ret = ov13858_get_regulators(ov13858); -+ if (ret) -+ return dev_err_probe(&client->dev, ret, -+ "Error fetching regulators\n"); -+ -+ ret = ov13858_get_gpios(ov13858); -+ if (ret) -+ return ret; -+ -+ ret = ov13858_sensor_powerup(ov13858); -+ if (ret) -+ return ret; // No cleanup needed yet, devm handles GPIOs/regulators -+ - /* Check module identity */ - ret = ov13858_identify_module(ov13858); - if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); -- return ret; -+ goto error_power_off; // Now we need to power down - } - - /* Set default mode to max resolution */ -@@ -1686,7 +1837,7 @@ - - ret = ov13858_init_controls(ov13858); - if (ret) -- return ret; -+ goto error_power_off; - - /* Initialize subdev */ - ov13858->sd.internal_ops = &ov13858_internal_ops; -@@ -1722,6 +1873,9 @@ - - error_handler_free: - ov13858_free_controls(ov13858); -+ -+error_power_off: -+ ov13858_sensor_powerdown(ov13858); - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); - - return ret; -@@ -1737,6 +1891,9 @@ - ov13858_free_controls(ov13858); - - pm_runtime_disable(&client->dev); -+ if (!pm_runtime_status_suspended(&client->dev)) -+ ov13858_sensor_powerdown(ov13858); -+ pm_runtime_set_suspended(&client->dev); - } - - static const struct i2c_device_id ov13858_id_table[] = { -@@ -1758,6 +1915,7 @@ - static struct i2c_driver ov13858_i2c_driver = { - .driver = { - .name = "ov13858", -+ .pm = &ov13858_pm_ops, - .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), - }, - .probe = ov13858_probe, - ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -205,6 +205,14 @@ - *con_id = "dvdd"; - *gpio_flags = GPIO_ACTIVE_HIGH; - break; -+ case 0x08: /* Surface Pro 9 - additional power rail */ -+ *con_id = "pwr1"; -+ *gpio_flags = GPIO_ACTIVE_HIGH; -+ break; -+ case 0x10: /* Surface Pro 9 - secondary power rail */ -+ *con_id = "pwr2"; -+ *gpio_flags = GPIO_ACTIVE_HIGH; -+ break; - default: - *con_id = "unknown"; - *gpio_flags = GPIO_ACTIVE_HIGH; -@@ -307,6 +315,8 @@ - case INT3472_GPIO_TYPE_PRIVACY_LED: - case INT3472_GPIO_TYPE_POWER_ENABLE: - case INT3472_GPIO_TYPE_HANDSHAKE: -+ case 0x08: /* Surface Pro 9 power rails */ -+ case 0x10: - gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); - if (IS_ERR(gpio)) { - ret = PTR_ERR(gpio); -@@ -345,6 +355,19 @@ - err_msg = "Failed to map handshake to sensor\n"; - - break; -+ case 0x08: /* Surface Pro 9 - treat as power*/ -+ dev_info(int3472->dev, "GPIO type 0x%02x detected on pin 0x%02x\n", type, agpio->pin_table[0]); -+ dev_info(int3472->dev, " con_id=%s, flags=0x%x\n", con_id, gpio_flags); -+ ret = skl_int3472_register_regulator(int3472, gpio, -+ GPIO_REGULATOR_ENABLE_TIME, -+ con_id, NULL); -+ dev_info(int3472->dev, " register_regulator returned: %d\n", ret); -+ if (ret) { -+ dev_err(int3472->dev, "Failed to register type 0x02x: %d\n", type, ret); -+ } -+ break; -+ case 0x10: -+ break; - default: /* Never reached */ - ret = -EINVAL; - break; - From 0f3a680444942cdbe8cf19ebc2a5b74cdad6929d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 01:21:25 +0100 Subject: [PATCH 148/236] Bump release version --- pkg/arch/kernel/0016-hid-surface.patch | 1 + pkg/arch/kernel/PKGBUILD | 34 ++++++++++--------- pkg/debian/kernel/version.conf | 2 +- .../kernel-surface/build-linux-surface.py | 2 +- 4 files changed, 21 insertions(+), 18 deletions(-) create mode 120000 pkg/arch/kernel/0016-hid-surface.patch diff --git a/pkg/arch/kernel/0016-hid-surface.patch b/pkg/arch/kernel/0016-hid-surface.patch new file mode 120000 index 0000000000..61f0abcdd8 --- /dev/null +++ b/pkg/arch/kernel/0016-hid-surface.patch @@ -0,0 +1 @@ +../../../patches/6.17/0016-hid-surface.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 6f3528f9b4..98ce98e6cb 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -4,7 +4,7 @@ pkgbase=linux-surface pkgver=6.17.9.arch1 -pkgrel=1 +pkgrel=2 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -57,6 +57,7 @@ source=( 0013-cameras.patch 0014-amd-gpio.patch 0015-rtc.patch + 0016-hid-surface.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds @@ -67,21 +68,22 @@ sha256sums=('96b647bf9499b9378acd66b174f1d97078cb26a38029545041a443998fe026de' '57786a01f3cfaeb696f79bf3b19996f7f787df3df8c6fbf6a9654aced518ec93' 'ee110be98c41a45302b2b81b037e3c4392ea7f142282e28400ac67b37455d42a' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - 'b226336b2817ad3d6f657bfc0d3156d4c827839254959a64e326ad3874f998bf' - '3618b7046cdf9b396b64d00fd8520498ed7d57e1910e020a127ca455837c9ec5' - '8b40cd801a9f440a5290aeb01df47470901cc2134efb04a4264ba404ddd45d57' - '9c3eacb2b12cef6c05dcdc7d2ff0ab18143e087819223494835bdf84afb78b5f' - '99b1118e0949422826a5c74ffb764040c8c36e5bb3a5cc86b688da8e600b260e' - '5c42ed2768cd2c3b905ef074eed0dd42b8784bbad1b9f30954932862a6b03641' - '8ef25afa0e0eb3c3db7105664952b2a24b6eabff0b93fa09f634c556dfec49b1' - 'f86649692c36bcd817920794dd28c287eaa673a885ebd6dbd5c6a0e31a243be9' - '490ac2b0c7a2ce95fa6f764cd7e727685b51fe1c06e528fe6ffb2989e53b22d2' - 'a60fa1d25b71f6b94fdb8a6b7f8935d79fa6c4fcf347c403b3f3f2ab8755eb6a' - '4c9771739d67d5704818405390acadb09882433e185837db5f3ca71c86d4c1f3' - '9c9633bf05c7198f0076dfbdc68007c594d5b22f91615920a60a0dd2f1eac5d9' - 'ed39543bd42481cf4ca3374e51380671bb2f28d1a860269b4324147b56fbeeba' - '09c7435d1a0069d17adf037a881f6765a7717e9fe82c5c2fa3d8bb6e09405410' - 'c382fa5be5966efefaa90bbf0e49f2a5a43e62ec4556defbd4fb48d2bc09ea21') + 'c24f56cd1ffead0411c325ee65c264cfc2f88b061f82a808711a7f0c9a46aad2' + '5a3f6a1a20f6d129bfda2c2426733feab2d023df6671af87f3e8e47e43871b73' + 'd8ada346c1d56c52a47ed04682abb13d94752bd44a604eec5a5bf578de2fdc6e' + '1780f4aa9e5b483a7c9ea6921504f5424007eb3bbf0ef82660bcaf942e067c5d' + 'f0ef8936532e96abc2b8158a657eb6748f4468e396368140e2410c5b114bd69f' + '354ba0dfc8985363fcccb3f561e4886707db11aedce9dfe62dd178b0ee687acb' + 'eaa7bbb8a86713f807595ad90a80346969e1f0d7d3826f1d40360d54518b97b1' + 'b1506ee10ed0c18e2a6a2cc856647512f67897b79eaa018fc4bf46ae4620d2a1' + '4bf6eb62ba85703f58bbb01e2a2e799231ee09bf936781899a909371c0f23374' + '8806664615edf5056317d922ae8aaa5526a48ff123ea1704a756bb6e772df776' + '40f9baea1875983a3d69915b05fb2fbb122e0ac27090079c41452186b48f83d5' + '46d3246dbda5ae825752ead189dec1e62c8d9c4b3b94c079025bf0768646d708' + '02b06ecf4202d6657d6ddbbc4594df8a98cdb77d4ae0d08b6c99377bbe58a3e7' + '56953242710bed28c7a92de3f7e40f27ab47d83ffce272bb5d107ac70c4deee1' + 'cd9620285ad69cc6c93d92e8070237d5f7a123b7337931adc487b1053d7b2599' + '76e6c300a2a29f56e45f7dfdadf640bb8ffa36cbe51c2c7674f32bf4e4439133') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 653f27adc2..10d8102cfa 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ KERNEL_VERSION="6.17.13" -KERNEL_REVISION="1" +KERNEL_REVISION="2" KERNEL_LOCALVERSION="-surface" diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index d413ee54c0..dbcda023d0 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -25,7 +25,7 @@ ## The release number of the modified kernel package. ## e.g. 300 for kernel-6.3.1-300.fc38.foo ## -PACKAGE_RELEASE = "1" +PACKAGE_RELEASE = "2" ## ## Build options for configuring which parts of the kernel package are enabled. From 8fada708106c639a699e63b818f0cba401bc2cd0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 01:41:02 +0100 Subject: [PATCH 149/236] pkg/fedora: Use 3-way merge for 'git am' --- pkg/fedora/kernel-surface/build-ark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-ark.py b/pkg/fedora/kernel-surface/build-ark.py index 2fa9201044..861cc7963c 100755 --- a/pkg/fedora/kernel-surface/build-ark.py +++ b/pkg/fedora/kernel-surface/build-ark.py @@ -113,7 +113,7 @@ def system(cmd: str) -> None: # Apply patches for patch in patches: - system("git am '%s'" % patch) + system("git am -3 '%s'" % patch) # Copy files for file in files: From 298dd760c5973930b31789ee3ba9bfa22050614d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 01:58:08 +0100 Subject: [PATCH 150/236] config: Add CONFIG_HID_SURFACE=m for hid-surface support --- configs/surface-6.17.config | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/surface-6.17.config b/configs/surface-6.17.config index a026c661b5..016efc4198 100644 --- a/configs/surface-6.17.config +++ b/configs/surface-6.17.config @@ -83,3 +83,4 @@ CONFIG_SURFACE_3_POWER_OPREGION=m CONFIG_SURFACE_PRO3_BUTTON=m CONFIG_SURFACE_GPE=m CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m +CONFIG_HID_SURFACE=m From 791e0798c9d63d39d3e88b21153a383a44a45765 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 02:10:13 +0100 Subject: [PATCH 151/236] pkg/arch: Update pkgsums --- pkg/arch/kernel/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 98ce98e6cb..6078b41322 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -66,7 +66,7 @@ validpgpkeys=( ) sha256sums=('96b647bf9499b9378acd66b174f1d97078cb26a38029545041a443998fe026de' '57786a01f3cfaeb696f79bf3b19996f7f787df3df8c6fbf6a9654aced518ec93' - 'ee110be98c41a45302b2b81b037e3c4392ea7f142282e28400ac67b37455d42a' + '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' 'c24f56cd1ffead0411c325ee65c264cfc2f88b061f82a808711a7f0c9a46aad2' '5a3f6a1a20f6d129bfda2c2426733feab2d023df6671af87f3e8e47e43871b73' From 611d307f4dd8fc1f45be96080d6463a2cfd11cd1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 12:56:02 +0100 Subject: [PATCH 152/236] Update v6.17 patches Changes: - Prevent mode set on the Surface Laptop Studio 2 touch pad (@LegendaryFire) --- patches/6.17/0016-hid-surface.patch | 88 +++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/patches/6.17/0016-hid-surface.patch b/patches/6.17/0016-hid-surface.patch index 2aec0deaec..4dfae662b1 100644 --- a/patches/6.17/0016-hid-surface.patch +++ b/patches/6.17/0016-hid-surface.patch @@ -156,3 +156,91 @@ index 000000000000..a171ea65672f -- 2.52.0 +From 7391632cbb14114fbe7334e16f64cfebc03a4d74 Mon Sep 17 00:00:00 2001 +From: LegendaryFire +Date: Wed, 24 Dec 2025 00:54:44 -0800 +Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 + touch pad + +Patchset: hid-surface +--- + drivers/hid/hid-multitouch.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index dd200064e309..14d088fdabed 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -80,6 +80,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) + #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) ++#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(26) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -238,6 +239,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_SMART_TECH 0x0113 + #define MT_CLS_APPLE_TOUCHBAR 0x0114 + #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 ++#define MT_CLS_SURFACE_TOUCHPAD 0x0116 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -445,6 +447,10 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_WIN8_PTP_BUTTONS, + .export_all_inputs = true + }, ++ { .name = MT_CLS_SURFACE_TOUCHPAD, ++ .quirks = MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE ++ }, + { } + }; + +@@ -2133,11 +2139,30 @@ static void mt_remove(struct hid_device *hdev) + + static void mt_on_hid_hw_open(struct hid_device *hdev) + { ++ /* ++ * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck ++ * non-functional if we change touchpad reporting modes from the HID ++ * open/close hooks. Avoid mode switching on hw_open/hw_close for ++ * those devices. ++ */ ++ struct mt_device *td = hid_get_drvdata(hdev); ++ if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) ++ return; + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + } + + static void mt_on_hid_hw_close(struct hid_device *hdev) + { ++ /* ++ * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck ++ * non-functional if we change touchpad reporting modes from the HID ++ * open/close hooks. Avoid mode switching on hw_open/hw_close for ++ * those devices. ++ */ ++ struct mt_device *td = hid_get_drvdata(hdev); ++ if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) ++ return; ++ + mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); + } + +@@ -2574,6 +2599,11 @@ static const struct hid_device_id mt_devices[] = { + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, + USB_VENDOR_ID_MICROSOFT, 0x09c0) }, + ++ /* Microsoft Surface touch pad */ ++ { .driver_data = MT_CLS_SURFACE_TOUCHPAD, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x0C46) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.52.0 + From bd6e5250f5b2ddf5f7fc861d9e077de6f9a7ef93 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 14:16:10 +0100 Subject: [PATCH 153/236] pkg/fedora: Bump release --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index dbcda023d0..49af946600 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -25,7 +25,7 @@ ## The release number of the modified kernel package. ## e.g. 300 for kernel-6.3.1-300.fc38.foo ## -PACKAGE_RELEASE = "2" +PACKAGE_RELEASE = "3" ## ## Build options for configuring which parts of the kernel package are enabled. From 44ff242eee2999b6f616c27f321a893ab452c5f5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 14:31:17 +0100 Subject: [PATCH 154/236] Add patches for 6.18 Derived from latest 6.17 patches Links: - kernel: https://github.com/linux-surface/kernel/commit/1cc181c914274d50fcb69c7c8d7db9a691811f2c - tree-devel: https://github.com/linux-surface/kernel/tree/v6.18-surface-devel - tree-patches: https://github.com/linux-surface/kernel/tree/v6.18-surface --- configs/surface-6.18.config | 86 + patches/6.18/0001-secureboot.patch | 112 + patches/6.18/0002-surface3.patch | 234 ++ patches/6.18/0003-mwifiex.patch | 400 +++ patches/6.18/0004-ath10k.patch | 120 + patches/6.18/0005-ipts.patch | 3243 ++++++++++++++++++ patches/6.18/0006-ithc.patch | 2780 +++++++++++++++ patches/6.18/0007-surface-sam.patch | 211 ++ patches/6.18/0008-surface-sam-over-hid.patch | 308 ++ patches/6.18/0009-surface-button.patch | 149 + patches/6.18/0010-surface-typecover.patch | 575 ++++ patches/6.18/0011-surface-shutdown.patch | 97 + patches/6.18/0012-surface-gpe.patch | 51 + patches/6.18/0013-cameras.patch | 1019 ++++++ patches/6.18/0014-amd-gpio.patch | 109 + patches/6.18/0015-rtc.patch | 110 + patches/6.18/0016-hid-surface.patch | 246 ++ 17 files changed, 9850 insertions(+) create mode 100644 configs/surface-6.18.config create mode 100644 patches/6.18/0001-secureboot.patch create mode 100644 patches/6.18/0002-surface3.patch create mode 100644 patches/6.18/0003-mwifiex.patch create mode 100644 patches/6.18/0004-ath10k.patch create mode 100644 patches/6.18/0005-ipts.patch create mode 100644 patches/6.18/0006-ithc.patch create mode 100644 patches/6.18/0007-surface-sam.patch create mode 100644 patches/6.18/0008-surface-sam-over-hid.patch create mode 100644 patches/6.18/0009-surface-button.patch create mode 100644 patches/6.18/0010-surface-typecover.patch create mode 100644 patches/6.18/0011-surface-shutdown.patch create mode 100644 patches/6.18/0012-surface-gpe.patch create mode 100644 patches/6.18/0013-cameras.patch create mode 100644 patches/6.18/0014-amd-gpio.patch create mode 100644 patches/6.18/0015-rtc.patch create mode 100644 patches/6.18/0016-hid-surface.patch diff --git a/configs/surface-6.18.config b/configs/surface-6.18.config new file mode 100644 index 0000000000..016efc4198 --- /dev/null +++ b/configs/surface-6.18.config @@ -0,0 +1,86 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +CONFIG_RTC_DRV_SURFACE=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m +CONFIG_INTEL_THC_HID=m +CONFIG_INTEL_QUICKSPI=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m +CONFIG_HID_SURFACE=m diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch new file mode 100644 index 0000000000..c386ade7ba --- /dev/null +++ b/patches/6.18/0001-secureboot.patch @@ -0,0 +1,112 @@ +From d6fc570bbe52fc8a59710505fae4330930dc9583 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index 9bea5a1e2c52..25848f886ad6 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLLCHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.52.0 + +From 4c96a0c3cedd2513ef41b7bcb393ee2713b28433 Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 6c42061ca20e..f7cb5669b5fb 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3342,6 +3342,11 @@ + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 26e45f86b955..8ec46d4565a0 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -38,6 +38,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -109,7 +110,7 @@ bool hibernation_in_progress(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1489,6 +1490,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1546,3 +1553,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.52.0 + diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch new file mode 100644 index 0000000000..2d259c03f1 --- /dev/null +++ b/patches/6.18/0002-surface3.patch @@ -0,0 +1,234 @@ +From 3cf19f7024c337cb241bdac922aa4f7c49230d2d Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3 +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index 6c8fb7a4dde4..22797a53f4d8 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index 29a403526cd9..986f32132c3d 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3792,6 +3792,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.52.0 + +From e7be2c605bdf261b99181c9c316c11b7bb3429c2 Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Fri, 6 Dec 2019 23:10:30 +0900 +Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by + default + +On Arch Linux kernel at least after 4.19, touch input is broken after suspend +(s2idle). + + kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + +On recent stable Arch Linux kernel (at least after 5.1), touch input will +crash after the first touch. + + kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue + +I found on an affected system (Arch Linux kernel, etc.), the touchscreen +driver uses DMA mode by default. Then, we found some kernels with different +kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel +chromeos-4.19 [2]) will use PIO mode by default and no such issues there. + +So, this commit disables DMA mode on the touchscreen driver side as a quick +workaround to avoid touch input crash. +We may need to properly set up DMA mode to use the touchscreen driver with +DMA mode. + +You can still switch DMA/PIO mode if you want: + + switch to DMA mode (maybe broken) + echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma + back to PIO mode + echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma + +Link to issue: https://github.com/jakeday/linux-surface/issues/596 + +References: +[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config +[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 + +Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. +This commit made the driver use PIO by default and no touch input crash. +Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default +even without this commit. After this commit, it still uses PIO and confirmed +no functional changes regarding touch input. + +More details: + We can confirm which mode the touchscreen driver uses; first, enable + debug output: + + echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + + Then, try to make a touch input and see dmesg log + + (On Arch Linux kernel, uses DMA) + kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA + kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 + c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + + (On the kernels I referenced above, uses PIO) + kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO + kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 + 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Note (2025-03-08): This patch was originally dropped due to the +comments in [3]. However, according to the commments in [4] it is still +required. + +[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a +[4]: https://github.com/linux-surface/linux-surface/issues/1184 + +Patchset: surface3 +--- + drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c +index 6074b7730e86..6aa3e1d6f160 100644 +--- a/drivers/input/touchscreen/surface3_spi.c ++++ b/drivers/input/touchscreen/surface3_spi.c +@@ -25,6 +25,12 @@ + #define SURFACE3_REPORT_TOUCH 0xd2 + #define SURFACE3_REPORT_PEN 0x16 + ++bool use_dma = false; ++module_param(use_dma, bool, 0644); ++MODULE_PARM_DESC(use_dma, ++ "Disable DMA mode if you encounter touch input crash. " ++ "(default: false, disabled to avoid crash)"); ++ + struct surface3_ts_data { + struct spi_device *spi; + struct gpio_desc *gpiod_rst[2]; +@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) + return 0; + } + ++static bool surface3_spi_can_dma(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) ++{ ++ return use_dma; ++} ++ + static int surface3_spi_probe(struct spi_device *spi) + { + struct surface3_ts_data *data; +@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) + if (error) + return error; + ++ /* ++ * Set up DMA ++ * ++ * TODO: Currently, touch input with DMA seems to be broken. ++ * On 4.19 LTS, touch input will crash after suspend. ++ * On recent stable kernel (at least after 5.1), touch input will crash after ++ * the first touch. No problem with PIO on those kernels. ++ * Maybe we need to configure DMA here. ++ * ++ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 ++ */ ++ spi->controller->can_dma = surface3_spi_can_dma; ++ + return 0; + } + +-- +2.52.0 + diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch new file mode 100644 index 0000000000..1b983842a6 --- /dev/null +++ b/patches/6.18/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From 789e7b03d5dcb9855effc613417cc90809934f83 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index a760de191fce..db9b203226a8 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.52.0 + +From fbdeed3f7949e8ceda8aa6d2c1be6c642cd8a07e Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index db9b203226a8..ffd0c1fe9223 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.52.0 + +From 79e33cc32e6967326cc481ed46455256bbff0412 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index fa683bb7f0b4..f80e194aa970 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) + #define BTUSB_BARROT BIT(28) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(29) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -472,6 +473,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -4177,6 +4179,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.52.0 + diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch new file mode 100644 index 0000000000..c9684d0470 --- /dev/null +++ b/patches/6.18/0004-ath10k.patch @@ -0,0 +1,120 @@ +From 718f88769376a3d9ef0f82f30be3966b87e852f3 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index 9ae3595fb698..b26a39c97998 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -41,6 +41,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -53,6 +56,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -62,6 +68,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -932,6 +941,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -946,6 +991,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.52.0 + diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch new file mode 100644 index 0000000000..140c73e722 --- /dev/null +++ b/patches/6.18/0005-ipts.patch @@ -0,0 +1,3243 @@ +From 19f6c954871b35178a9a87aec7ec52f538a9bfb6 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index a4f75dc36929..e4a561b257d7 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 73cad914be9f..807e352af059 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.52.0 + +From 52d2afc33b2e824f47c7a4f32dc637ca8fc72f45 Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index e236c7ec221f..9e31a5fe1f66 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -39,6 +39,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -209,12 +214,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + static const struct iommu_dirty_ops intel_dirty_ops; +@@ -1879,6 +1886,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -2169,6 +2179,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -4515,6 +4528,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -4553,6 +4578,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.52.0 + +From 20e764ff7f650b1b6472e06d0b8e43bf72cb98e7 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 04420a713be0..63b4eda94db2 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1439,6 +1439,8 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 361a7daedeb8..b73a1bbd3a1d 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -176,3 +176,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.52.0 + diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch new file mode 100644 index 0000000000..50f3fb5208 --- /dev/null +++ b/patches/6.18/0006-ithc.patch @@ -0,0 +1,2780 @@ +From c7f172907387d835fb993fbbfa9260375026bd97 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 4f9b01dc91e8..e4d73e45473c 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.52.0 + +From a8912e19c8afad3e6c24d9ea5184c590f1eeaa51 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 438 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2575 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 63b4eda94db2..184a2b2f9347 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1441,6 +1441,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index b73a1bbd3a1d..3190ece25626 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -178,3 +178,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..094d878d671b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,438 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) }, ++ // MTL and up are handled by drivers/hid/intel-thc-hid ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ timer_delete_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.52.0 + diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch new file mode 100644 index 0000000000..ec207921ba --- /dev/null +++ b/patches/6.18/0007-surface-sam.patch @@ -0,0 +1,211 @@ +From 3850f3e3beff859fab3d3d0b1f6e0be3fc4d46dc Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 17 Jun 2022 02:14:00 +0200 +Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator + Module + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/rtc/Kconfig | 7 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 drivers/rtc/rtc-surface.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 2933c41c77c8..050eba74d8a2 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1399,6 +1399,13 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_SURFACE ++ tristate "Microsoft Surface Aggregator RTC" ++ depends on SURFACE_AGGREGATOR ++ depends on SURFACE_AGGREGATOR_BUS ++ help ++ TODO ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 8221bda6e6dc..8932df6e03ed 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -183,6 +183,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o + obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o + obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o + obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o ++obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o +diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c +new file mode 100644 +index 000000000000..f6c17c4e98d5 +--- /dev/null ++++ b/drivers/rtc/rtc-surface.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * AC driver for 7th-generation Microsoft Surface devices via Surface System ++ * Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2019-2021 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct surface_rtc { ++ struct ssam_device *sdev; ++ struct rtc_device *rtc; ++}; ++ ++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x10, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x0f, ++}); ++ ++static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) ++{ ++ __le32 time_le; ++ int status; ++ ++ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); ++ if (status) ++ return status; ++ ++ *time = le32_to_cpu(time_le); ++ return 0; ++} ++ ++static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) ++{ ++ __le32 time_le = cpu_to_le32(time); ++ ++ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); ++} ++ ++static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ int status; ++ u32 time; ++ ++ status = ssam_rtc_get_unix_time(srtc, &time); ++ if (status) ++ return status; ++ ++ rtc_time64_to_tm(time, tm); ++ return 0; ++} ++ ++static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ time64_t time = rtc_tm_to_time64(tm); ++ ++ return ssam_rtc_set_unix_time(srtc, (u32)time); ++} ++ ++static const struct rtc_class_ops surface_rtc_ops = { ++ .read_time = surface_rtc_read_time, ++ .set_time = surface_rtc_set_time, ++}; ++ ++static int surface_rtc_probe(struct ssam_device *sdev) ++{ ++ struct surface_rtc *srtc; ++ ++ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->sdev = sdev; ++ ++ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); ++ if (IS_ERR(srtc->rtc)) ++ return PTR_ERR(srtc->rtc); ++ ++ srtc->rtc->ops = &surface_rtc_ops; ++ srtc->rtc->range_max = U32_MAX; ++ ++ ssam_device_set_drvdata(sdev, srtc); ++ ++ return devm_rtc_register_device(srtc->rtc); ++} ++ ++static void surface_rtc_remove(struct ssam_device *sdev) ++{ ++ /* Device-managed allocations take care of everything... */ ++} ++ ++static const struct ssam_device_id surface_rtc_match[] = { ++ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, surface_rtc_match); ++ ++static struct ssam_device_driver surface_rtc_driver = { ++ .probe = surface_rtc_probe, ++ .remove = surface_rtc_remove, ++ .match_table = surface_rtc_match, ++ .driver = { ++ .name = "surface_rtc", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(surface_rtc_driver); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.52.0 + +From 1935dca81444254be728b48fefc3ce42f2d3c3da Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 20 Apr 2025 01:05:14 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 + (ACPI) + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index a594d5fcfcfd..07b03aa4fa7f 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Laptop 6 */ + { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + ++ /* Surface Laptop 7 */ ++ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.52.0 + diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch new file mode 100644 index 0000000000..75cdd15e94 --- /dev/null +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From b0afc4791a622f2f35a94f4be73f560d08967128 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index ed90858a27b7..070c36637811 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -763,6 +784,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.52.0 + +From ec63ad179736cec451a38c2a55cbc1ebb8d31356 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index f775c6ca1ec1..2075e3852053 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.52.0 + diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch new file mode 100644 index 0000000000..d050f23647 --- /dev/null +++ b/patches/6.18/0009-surface-button.patch @@ -0,0 +1,149 @@ +From 77d4b30b68796c78613ba69c4a53745531d774f9 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index b8cad415c62c..43b5d56383e3 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.52.0 + +From 7c2976cf057b485aca52b60a0969de085f75b0f0 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.52.0 + diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch new file mode 100644 index 0000000000..bd3d0c953f --- /dev/null +++ b/patches/6.18/0010-surface-typecover.patch @@ -0,0 +1,575 @@ +From cf96145d5c827b8fcc831e6ff05f76a27ab4713b Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 47f589c4104a..6b00aec67ee2 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.52.0 + +From 27182ab01f104e701b0f2fe835a4d257176c156c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 179dc316b4b5..7d644e1c445e 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -35,7 +35,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + #include "hid-haptic.h" + +@@ -76,12 +80,15 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #define MT_BUTTONTYPE_CLICKPAD 0 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -184,6 +191,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -229,6 +238,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 + #define MT_CLS_APPLE_TOUCHBAR 0x0114 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -425,6 +435,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1842,6 +1862,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1870,6 +1953,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1908,8 +1994,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && + !hid_find_field(hdev, HID_INPUT_REPORT, +@@ -1923,8 +2011,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1985,6 +2075,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2429,6 +2520,11 @@ static const struct hid_device_id mt_devices[] = { + HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.52.0 + +From 5bc896710a3e3db40f4b7351585eb811f3673087 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 7d644e1c445e..0eb4f7d1228e 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -81,6 +81,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -88,6 +89,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -437,6 +440,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1463,6 +1467,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1490,6 +1497,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1516,6 +1538,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1523,6 +1546,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1532,11 +1568,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1719,6 +1765,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1776,6 +1858,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1862,30 +1951,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1894,8 +1959,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -2053,13 +2119,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -2068,12 +2145,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); +-- +2.52.0 + diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch new file mode 100644 index 0000000000..8895404c2e --- /dev/null +++ b/patches/6.18/0011-surface-shutdown.patch @@ -0,0 +1,97 @@ +From 4864694f8b95bf1bdffc5fd607334c408d9b73c6 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 302d61783f6c..4a8a08bd92dd 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index b9c252aa6fe0..ce4c0da99537 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6341,3 +6341,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index bf97d49c23cf..90eead93d825 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -487,6 +487,7 @@ struct pci_dev { + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ + unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.52.0 + diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch new file mode 100644 index 0000000000..d7645e2ff2 --- /dev/null +++ b/patches/6.18/0012-surface-gpe.patch @@ -0,0 +1,51 @@ +From 4145812a4cb6093d473918ce72f693dd47c9c586 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index b359413903b1..b4496db79f39 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.52.0 + diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch new file mode 100644 index 0000000000..b58adc827a --- /dev/null +++ b/patches/6.18/0013-cameras.patch @@ -0,0 +1,1019 @@ +From fb2e71467ce8c2b49ba8b1993ed6cf6695d35371 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index ef16d58b2949..a6bad2679a0c 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.52.0 + +From 4d2eeed56d6d694a2068edbf1cf9c80ff53c143e Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 9e31a5fe1f66..bdd32551c452 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -44,6 +44,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -215,12 +222,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -1887,6 +1896,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -2179,6 +2191,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -4528,6 +4543,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -4578,6 +4605,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.52.0 + +From 7eca7549a279d6424558df5b9b18447830763f9e Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 0133405697dc..9e0763bdc758 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.52.0 + +From a45541d86bd42201c0f6c34c164ff6bf5ff43454 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 27afc3fc0175..28b192c9a5ec 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1579,7 +1579,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.52.0 + +From 3eebeb1855e4459c7a55828ca2cbbe29952531d4 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index cb153ce42c45..f11b499e14bb 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.52.0 + +From f6625936b705d9198988eb6d5beb9e0c3531e5cf Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 9e0763bdc758..0976b267972b 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.52.0 + +From 83ea382cbc7c27b5b2876ed187a79aae8e4f44d7 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.52.0 + +From fbb539345d7b7399b642c8ac3960a4001ade98fa Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 06e6291be11b..8f94924ef379 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -1002,6 +1002,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 9a0333ec1a86..4e1ca8fc9b41 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_UPBOARD) += leds-upboard.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.52.0 + +From 6cd252af01846bf35a2968baccc8d427ff6fa660 Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index 032fbcb981f2..e03a1d8cdcb4 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -87,6 +87,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); + fsleep(100); +-- +2.52.0 + +From 749e03034a13b36f5ccf23e9f9fc71057ea430bc Mon Sep 17 00:00:00 2001 +From: Tooraj Taraz +Date: Wed, 31 Dec 2025 00:35:50 +0100 +Subject: [PATCH] Add camera support for Surface Pro 9 + +Experimental camera support for the Surface Pro 9. + +Link: https://github.com/linux-surface/linux-surface/pull/1867 +Patchset: cameras +--- + drivers/media/i2c/ov13858.c | 158 +++++++++++++++++- + drivers/media/i2c/ov5693.c | 1 + + drivers/media/pci/intel/ipu-bridge.c | 4 + + drivers/platform/x86/intel/int3472/discrete.c | 23 +++ + 4 files changed, 184 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c +index 162b49046990..85cd0c98af03 100644 +--- a/drivers/media/i2c/ov13858.c ++++ b/drivers/media/i2c/ov13858.c +@@ -2,6 +2,7 @@ + // Copyright (c) 2017 Intel Corporation. + + #include ++#include + #include + #include + #include +@@ -119,6 +120,14 @@ struct ov13858_mode { + struct ov13858_reg_list reg_list; + }; + ++// Or use standard names that might be more correct: ++static const char * const ov13858_supply_names[] = { ++ "avdd", // Analog voltage ++ "pwr1", // Digital core voltage ++}; ++ ++#define OV13858_NUM_SUPPLIES ARRAY_SIZE(ov13858_supply_names) ++ + /* 4224x3136 needs 1080Mbps/lane, 4 lanes */ + static const struct ov13858_reg mipi_data_rate_1080mbps[] = { + /* PLL1 registers */ +@@ -1046,12 +1055,126 @@ struct ov13858 { + /* Current mode */ + const struct ov13858_mode *cur_mode; + ++ struct regulator_bulk_data supplies[OV13858_NUM_SUPPLIES]; ++ struct gpio_desc *reset; ++ struct clk *xvclk; ++ + /* Mutex for serialized access */ + struct mutex mutex; + }; + + #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) + ++ ++static int ov13858_get_regulators(struct ov13858 *ov13858) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < OV13858_NUM_SUPPLIES; i++) ++ ov13858->supplies[i].supply = ov13858_supply_names[i]; ++ ++ return devm_regulator_bulk_get(ov13858->dev, OV13858_NUM_SUPPLIES, ++ ov13858->supplies); ++} ++ ++static int ov13858_sensor_powerup(struct ov13858 *ov13858) ++{ ++ int ret; ++ ++ dev_info(ov13858->dev, "Powering up sensor\n"); ++ ++ /* Assert reset */ ++ gpiod_set_value_cansleep(ov13858->reset, 1); ++ ++ /* Enable clock FIRST - sensor needs clock to communicate */ ++ ret = clk_prepare_enable(ov13858->xvclk); ++ if (ret) { ++ dev_err(ov13858->dev, "Failed to enable clock: %d\n", ret); ++ return ret; ++ } ++ dev_info(ov13858->dev, "Clock enabled\n"); ++ ++ /* Enable regulators */ ++ ret = regulator_bulk_enable(OV13858_NUM_SUPPLIES, ov13858->supplies); ++ if (ret) { ++ dev_err(ov13858->dev, "Failed to enable regulators: %d\n", ret); ++ clk_disable_unprepare(ov13858->xvclk); ++ return ret; ++ } ++ ++ dev_info(ov13858->dev, "Regulators enabled\n"); ++ ++ /* Wait for power to stabilize */ ++ usleep_range(5000, 10000); ++ ++ /* De-assert reset */ ++ gpiod_set_value_cansleep(ov13858->reset, 0); ++ ++ /* Wait for sensor to boot */ ++ msleep(20); ++ ++ dev_info(ov13858->dev, "Reset de-asserted, sensor should be ready\n"); ++ ++ return 0; ++} ++ ++static void ov13858_sensor_powerdown(struct ov13858 *ov13858) ++{ ++ dev_info(ov13858->dev, "Powering down sensor\n"); ++ ++ /* Assert reset to put sensor in reset state */ ++ gpiod_set_value_cansleep(ov13858->reset, 1); ++ ++ /* Disable regulators */ ++ regulator_bulk_disable(OV13858_NUM_SUPPLIES, ov13858->supplies); ++ dev_info(ov13858->dev, "Regulators disabled\n"); ++ ++ /* Disable clock */ ++ clk_disable_unprepare(ov13858->xvclk); ++ dev_info(ov13858->dev, "Clock disabled\n"); ++} ++ ++static int __maybe_unused ov13858_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov13858 *ov13858 = to_ov13858(sd); ++ ++ ov13858_sensor_powerdown(ov13858); ++ ++ return 0; ++} ++ ++static int __maybe_unused ov13858_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov13858 *ov13858 = to_ov13858(sd); ++ int ret; ++ ++ ret = ov13858_sensor_powerup(ov13858); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ov13858_pm_ops = { ++ SET_RUNTIME_PM_OPS(ov13858_suspend, ov13858_resume, NULL) ++}; ++ ++static int ov13858_get_gpios(struct ov13858 *ov13858) ++{ ++ ov13858->reset = devm_gpiod_get_optional(ov13858->dev, "reset", ++ GPIOD_OUT_HIGH); ++ if (IS_ERR(ov13858->reset)) { ++ dev_err(ov13858->dev, "Error fetching reset GPIO\n"); ++ return PTR_ERR(ov13858->reset); ++ } ++ ++ return 0; ++} ++ + /* Read registers up to 4 at a time */ + static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, + u32 *val) +@@ -1498,8 +1621,11 @@ static int ov13858_identify_module(struct ov13858 *ov13858) + int ret; + u32 val; + ++ dev_info(ov13858->dev, "Attempting to read chip ID from register 0x300a\n"); + ret = ov13858_read_reg(ov13858, OV13858_REG_CHIP_ID, + OV13858_REG_VALUE_24BIT, &val); ++ dev_info(ov13858->dev, "Chip ID read result: ret=%d, val=0x%06x (expected 0x%06x)\n", ++ ret, val, OV13858_CHIP_ID); + if (ret) + return ret; + +@@ -1509,6 +1635,7 @@ static int ov13858_identify_module(struct ov13858 *ov13858) + return -EIO; + } + ++ dev_info(ov13858->dev, "Chip ID verified successfully!\n"); + return 0; + } + +@@ -1678,14 +1805,33 @@ static int ov13858_probe(struct i2c_client *client) + "external clock %lu is not supported\n", + freq); + ++ /* Get the external clock */ ++ ov13858->xvclk = devm_clk_get_optional(ov13858->dev, "xvclk"); ++ if (IS_ERR(ov13858->xvclk)) ++ return dev_err_probe(ov13858->dev, PTR_ERR(ov13858->xvclk), ++ "failed to get xvclk\n"); ++ + /* Initialize subdev */ + v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops); + ++ ret = ov13858_get_regulators(ov13858); ++ if (ret) ++ return dev_err_probe(ov13858->dev, ret, ++ "Error fetching regulators\n"); ++ ++ ret = ov13858_get_gpios(ov13858); ++ if (ret) ++ return ret; ++ ++ ret = ov13858_sensor_powerup(ov13858); ++ if (ret) ++ return ret; // No cleanup needed yet, devm handles GPIOs/regulators ++ + /* Check module identity */ + ret = ov13858_identify_module(ov13858); + if (ret) { + dev_err(ov13858->dev, "failed to find sensor: %d\n", ret); +- return ret; ++ goto error_power_off; // Now we need to power down + } + + /* Set default mode to max resolution */ +@@ -1693,7 +1839,7 @@ static int ov13858_probe(struct i2c_client *client) + + ret = ov13858_init_controls(ov13858); + if (ret) +- return ret; ++ goto error_power_off; + + /* Initialize subdev */ + ov13858->sd.internal_ops = &ov13858_internal_ops; +@@ -1729,6 +1875,10 @@ static int ov13858_probe(struct i2c_client *client) + + error_handler_free: + ov13858_free_controls(ov13858); ++ ++error_power_off: ++ ov13858_sensor_powerdown(ov13858); ++ + dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret); + + return ret; +@@ -1744,6 +1894,9 @@ static void ov13858_remove(struct i2c_client *client) + ov13858_free_controls(ov13858); + + pm_runtime_disable(ov13858->dev); ++ if (!pm_runtime_status_suspended(ov13858->dev)) ++ ov13858_sensor_powerdown(ov13858); ++ pm_runtime_set_suspended(ov13858->dev); + } + + static const struct i2c_device_id ov13858_id_table[] = { +@@ -1765,6 +1918,7 @@ MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids); + static struct i2c_driver ov13858_i2c_driver = { + .driver = { + .name = "ov13858", ++ .pm = &ov13858_pm_ops, + .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), + }, + .probe = ov13858_probe, +diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c +index d294477f9dd3..46bc6c5b7758 100644 +--- a/drivers/media/i2c/ov5693.c ++++ b/drivers/media/i2c/ov5693.c +@@ -1396,6 +1396,7 @@ static const struct dev_pm_ops ov5693_pm_ops = { + + static const struct acpi_device_id ov5693_acpi_match[] = { + {"INT33BE"}, ++ {"OVTI5693"}, + {}, + }; + MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +index 4e579352ab2c..ac637207b644 100644 +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -60,6 +60,10 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { + IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), + /* Onsemi MT9M114 */ + IPU_SENSOR_CONFIG("INT33F0", 1, 384000000), ++ /* Omnivision OV5693 - Surface Pro 9 */ ++ IPU_SENSOR_CONFIG("OVTI5693", 1, 419200000), ++ /* Omnivision OV13858 - Surface Pro 9 */ ++ IPU_SENSOR_CONFIG("OVTID858", 4, 540000000), + /* Omnivision OV2740 */ + IPU_SENSOR_CONFIG("INT3474", 1, 180000000), + /* Omnivision OV5670 */ +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 1505fc3ef7a8..20962e8acb26 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -229,6 +229,14 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 + /* Setups using a handshake pin need 25 ms enable delay */ + *enable_time_us = 25 * USEC_PER_MSEC; + break; ++ case 0x08: /* Surface Pro 9 - additional power rail */ ++ *con_id = "pwr1"; ++ *gpio_flags = GPIO_ACTIVE_HIGH; ++ break; ++ case 0x10: /* Surface Pro 9 - secondary power rail */ ++ *con_id = "pwr2"; ++ *gpio_flags = GPIO_ACTIVE_HIGH; ++ break; + default: + *con_id = "unknown"; + *gpio_flags = GPIO_ACTIVE_HIGH; +@@ -333,6 +341,8 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, + case INT3472_GPIO_TYPE_PRIVACY_LED: + case INT3472_GPIO_TYPE_POWER_ENABLE: + case INT3472_GPIO_TYPE_HANDSHAKE: ++ case 0x08: /* Surface Pro 9 power rails */ ++ case 0x10: + gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); + if (IS_ERR(gpio)) { + ret = PTR_ERR(gpio); +@@ -363,6 +373,19 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, + err_msg = "Failed to register regulator\n"; + + break; ++ case 0x08: /* Surface Pro 9 - treat as power*/ ++ dev_info(int3472->dev, "GPIO type 0x%02x detected on pin 0x%02x\n", type, agpio->pin_table[0]); ++ dev_info(int3472->dev, " con_id=%s, flags=0x%x\n", con_id, gpio_flags); ++ ret = skl_int3472_register_regulator(int3472, gpio, ++ GPIO_REGULATOR_ENABLE_TIME, ++ con_id, NULL); ++ dev_info(int3472->dev, " register_regulator returned: %d\n", ret); ++ if (ret) { ++ dev_err(int3472->dev, "Failed to register type 0x02x: %d\n", type, ret); ++ } ++ break; ++ case 0x10: ++ break; + default: /* Never reached */ + ret = -EINVAL; + break; +-- +2.52.0 + diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch new file mode 100644 index 0000000000..72d596ec9e --- /dev/null +++ b/patches/6.18/0014-amd-gpio.patch @@ -0,0 +1,109 @@ +From e06ddb701b0458b770996b893ae0acf996f51d51 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 9fa321a95eb3..8914a922be2b 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1171,6 +1172,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1227,6 +1239,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.52.0 + +From 4532af4e877be51a6f501f99e76c6632214516e3 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 8914a922be2b..c43d0a553867 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.52.0 + diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch new file mode 100644 index 0000000000..740a0d0425 --- /dev/null +++ b/patches/6.18/0015-rtc.patch @@ -0,0 +1,110 @@ +From d5457f13b006eebde52dc706320ea546cdc0c9a0 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 33418dd6768a..f94bbdc1de06 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -481,15 +489,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -568,13 +575,18 @@ static void acpi_tad_remove(struct platform_device *pdev) + if (dd->capabilities & ACPI_TAD_RT) + sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -616,12 +628,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -652,6 +658,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.52.0 + diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch new file mode 100644 index 0000000000..56afd4a1fa --- /dev/null +++ b/patches/6.18/0016-hid-surface.patch @@ -0,0 +1,246 @@ +From 647ba0853323d287d240377d5ecfa79c9872e96f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= +Date: Fri, 10 Oct 2025 19:04:03 +0100 +Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) + +The Surface Aggregator Module firmware incorrectly reports the FN key +as BTN_0 (button 256) through runtime HID events. This button can get +stuck in pressed state, flooding the input system and breaking focus +tracking in KWin Wayland compositor. + +Add a new hid-surface driver that filters BTN_0 events using the event +callback. The FN key should be handled as a hardware modifier and not +reported to the OS. + +Tested on Surface Laptop 4 AMD with KDE Plasma Wayland. After the fix: +- FN key combinations work correctly (volume, brightness) +- Focus tracking no longer breaks +- Mouse clicks work on all windows + +Fixes: https://github.com/linux-surface/linux-surface/issues/1851 +Patchset: hid-surface +--- + drivers/hid/Kconfig | 8 ++++ + drivers/hid/Makefile | 1 + + drivers/hid/hid-surface.c | 90 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 99 insertions(+) + create mode 100644 drivers/hid/hid-surface.c + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 184a2b2f9347..d2e308b257b5 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1141,6 +1141,14 @@ config HID_SUNPLUS + help + Support for Sunplus wireless desktop. + ++config HID_SURFACE ++ tristate "Microsoft Surface" ++ depends on SURFACE_AGGREGATOR ++ help ++ Say Y here to enable HID driver for Microsoft Surface integrated ++ keyboard and touchpad. This driver filters out erroneous BTN_0 ++ (FN key) events that can cause input focus issues. ++ + config HID_RMI + tristate "Synaptics RMI4 device support" + select RMI4_CORE +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 3190ece25626..4d2891879548 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -174,6 +174,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++obj-$(CONFIG_HID_SURFACE) += hid-surface.o + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + +diff --git a/drivers/hid/hid-surface.c b/drivers/hid/hid-surface.c +new file mode 100644 +index 000000000000..a171ea65672f +--- /dev/null ++++ b/drivers/hid/hid-surface.c +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * HID driver for Microsoft Surface devices ++ * ++ * Copyright (c) 2025 Linux Surface Project ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++/* ++ * The Surface Aggregator Module firmware incorrectly reports the FN key ++ * as BTN_0 (button 256). This button can get stuck in pressed state, ++ * flooding the input system and breaking focus tracking in some ++ * compositors. Filter out BTN_0 as FN should be handled as a hardware ++ * modifier, not reported to the OS. ++ */ ++static int surface_input_mapping(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ /* ++ * Filter BTN_0 during input mapping in case it appears in the ++ * HID descriptor (defense in depth). ++ */ ++ if (usage->type == EV_KEY && usage->code == BTN_0) ++ return -1; /* Don't map this usage */ ++ ++ return 0; /* Use default mapping */ ++} ++ ++static int surface_event(struct hid_device *hdev, struct hid_field *field, ++ struct hid_usage *usage, __s32 value) ++{ ++ /* ++ * The Surface Aggregator Module firmware reports the FN key as BTN_0 ++ * at runtime. This button can get stuck in pressed state, flooding ++ * the input system and breaking focus tracking. Filter out these ++ * events as FN should be a hardware modifier, not reported to the OS. ++ */ ++ if (usage->type == EV_KEY && usage->code == BTN_0) ++ return 1; /* Event handled, don't process further */ ++ ++ return 0; /* Process event normally */ ++} ++ ++static int surface_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ int ret; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "parse failed\n"); ++ return ret; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ++ if (ret) { ++ hid_err(hdev, "hw start failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct hid_device_id surface_devices[] = { ++ { HID_DEVICE(BUS_HOST, HID_GROUP_GENERIC, ++ USB_VENDOR_ID_MICROSOFT, 0x09AE) }, /* Surface Keyboard */ ++ { HID_DEVICE(BUS_HOST, HID_GROUP_GENERIC, ++ USB_VENDOR_ID_MICROSOFT, 0x09AF) }, /* Surface Mouse/Touchpad */ ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, surface_devices); ++ ++static struct hid_driver surface_driver = { ++ .name = "surface", ++ .id_table = surface_devices, ++ .probe = surface_probe, ++ .input_mapping = surface_input_mapping, ++ .event = surface_event, ++}; ++module_hid_driver(surface_driver); ++ ++MODULE_AUTHOR("Linux Surface Project"); ++MODULE_DESCRIPTION("Microsoft Surface HID driver"); ++MODULE_LICENSE("GPL"); +-- +2.52.0 + +From 1cc181c914274d50fcb69c7c8d7db9a691811f2c Mon Sep 17 00:00:00 2001 +From: LegendaryFire +Date: Wed, 24 Dec 2025 00:54:44 -0800 +Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 + touch pad + +Patchset: hid-surface +--- + drivers/hid/hid-multitouch.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 0eb4f7d1228e..8f2ed29b4f35 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) + #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) ++#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(26) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -242,6 +243,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_SMART_TECH 0x0113 + #define MT_CLS_APPLE_TOUCHBAR 0x0114 + #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 ++#define MT_CLS_SURFACE_TOUCHPAD 0x0116 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -449,6 +451,10 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_WIN8_PTP_BUTTONS, + .export_all_inputs = true + }, ++ { .name = MT_CLS_SURFACE_TOUCHPAD, ++ .quirks = MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE ++ }, + { } + }; + +@@ -2180,11 +2186,30 @@ static void mt_remove(struct hid_device *hdev) + + static void mt_on_hid_hw_open(struct hid_device *hdev) + { ++ /* ++ * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck ++ * non-functional if we change touchpad reporting modes from the HID ++ * open/close hooks. Avoid mode switching on hw_open/hw_close for ++ * those devices. ++ */ ++ struct mt_device *td = hid_get_drvdata(hdev); ++ if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) ++ return; + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + } + + static void mt_on_hid_hw_close(struct hid_device *hdev) + { ++ /* ++ * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck ++ * non-functional if we change touchpad reporting modes from the HID ++ * open/close hooks. Avoid mode switching on hw_open/hw_close for ++ * those devices. ++ */ ++ struct mt_device *td = hid_get_drvdata(hdev); ++ if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) ++ return; ++ + mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); + } + +@@ -2621,6 +2646,11 @@ static const struct hid_device_id mt_devices[] = { + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, + USB_VENDOR_ID_MICROSOFT, 0x09c0) }, + ++ /* Microsoft Surface touch pad */ ++ { .driver_data = MT_CLS_SURFACE_TOUCHPAD, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x0C46) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.52.0 + From 500de820c75f81847488bedaee9b723f8910d52b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 14:39:14 +0100 Subject: [PATCH 155/236] Update Arch kernel to v6.18.2 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- pkg/arch/kernel/0007-surface-sam.patch | 2 +- .../kernel/0008-surface-sam-over-hid.patch | 2 +- pkg/arch/kernel/0009-surface-button.patch | 2 +- pkg/arch/kernel/0010-surface-typecover.patch | 2 +- pkg/arch/kernel/0011-surface-shutdown.patch | 2 +- pkg/arch/kernel/0012-surface-gpe.patch | 2 +- pkg/arch/kernel/0013-cameras.patch | 2 +- pkg/arch/kernel/0014-amd-gpio.patch | 2 +- pkg/arch/kernel/0015-rtc.patch | 2 +- pkg/arch/kernel/0016-hid-surface.patch | 2 +- pkg/arch/kernel/PKGBUILD | 40 ++-- pkg/arch/kernel/config | 220 +++++++++++------- pkg/arch/kernel/surface.config | 2 +- 19 files changed, 176 insertions(+), 118 deletions(-) diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 83770e7463..5b0195eb8d 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.17/0001-secureboot.patch \ No newline at end of file +../../../patches/6.18/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3.patch b/pkg/arch/kernel/0002-surface3.patch index 647d418669..35e0ba2241 120000 --- a/pkg/arch/kernel/0002-surface3.patch +++ b/pkg/arch/kernel/0002-surface3.patch @@ -1 +1 @@ -../../../patches/6.17/0002-surface3.patch \ No newline at end of file +../../../patches/6.18/0002-surface3.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index 8eff39c65b..64548e7d9d 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.17/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.18/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index e6965f8f99..52693d8bb3 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.17/0004-ath10k.patch \ No newline at end of file +../../../patches/6.18/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index 369f11a8c3..255fbd10cf 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.17/0005-ipts.patch \ No newline at end of file +../../../patches/6.18/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index 3c7e254ed2..fc3080a983 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.17/0006-ithc.patch \ No newline at end of file +../../../patches/6.18/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch index 53e981c842..6c09d90243 120000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -1 +1 @@ -../../../patches/6.17/0007-surface-sam.patch \ No newline at end of file +../../../patches/6.18/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch index 5658b9eae0..08f79dcde2 120000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -1 +1 @@ -../../../patches/6.17/0008-surface-sam-over-hid.patch \ No newline at end of file +../../../patches/6.18/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch index f66ee87442..7ff9dad876 120000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -1 +1 @@ -../../../patches/6.17/0009-surface-button.patch \ No newline at end of file +../../../patches/6.18/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch index 94a5d85ad3..9671bcc9b5 120000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -1 +1 @@ -../../../patches/6.17/0010-surface-typecover.patch \ No newline at end of file +../../../patches/6.18/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch index 226bc9909f..301ed6896e 120000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -1 +1 @@ -../../../patches/6.17/0011-surface-shutdown.patch \ No newline at end of file +../../../patches/6.18/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch index 3c0d80faa3..36c0968268 120000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -1 +1 @@ -../../../patches/6.17/0012-surface-gpe.patch \ No newline at end of file +../../../patches/6.18/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch index 0bc0237e89..a558b038bf 120000 --- a/pkg/arch/kernel/0013-cameras.patch +++ b/pkg/arch/kernel/0013-cameras.patch @@ -1 +1 @@ -../../../patches/6.17/0013-cameras.patch \ No newline at end of file +../../../patches/6.18/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch index 4bdec9445b..26387d23f1 120000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -1 +1 @@ -../../../patches/6.17/0014-amd-gpio.patch \ No newline at end of file +../../../patches/6.18/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch index 0f2b4686ce..ab76e5fea1 120000 --- a/pkg/arch/kernel/0015-rtc.patch +++ b/pkg/arch/kernel/0015-rtc.patch @@ -1 +1 @@ -../../../patches/6.17/0015-rtc.patch \ No newline at end of file +../../../patches/6.18/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0016-hid-surface.patch b/pkg/arch/kernel/0016-hid-surface.patch index 61f0abcdd8..721d18b34c 120000 --- a/pkg/arch/kernel/0016-hid-surface.patch +++ b/pkg/arch/kernel/0016-hid-surface.patch @@ -1 +1 @@ -../../../patches/6.17/0016-hid-surface.patch \ No newline at end of file +../../../patches/6.18/0016-hid-surface.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 6078b41322..69d754643c 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,8 +3,8 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.17.9.arch1 -pkgrel=2 +pkgver=6.18.2.arch2 +pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -64,26 +64,26 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('96b647bf9499b9378acd66b174f1d97078cb26a38029545041a443998fe026de' - '57786a01f3cfaeb696f79bf3b19996f7f787df3df8c6fbf6a9654aced518ec93' +sha256sums=('63794d6bd1c8f2ca7a023ce333e3a26c423637dd0fdefe612e2950e6604190b6' + 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - 'c24f56cd1ffead0411c325ee65c264cfc2f88b061f82a808711a7f0c9a46aad2' - '5a3f6a1a20f6d129bfda2c2426733feab2d023df6671af87f3e8e47e43871b73' - 'd8ada346c1d56c52a47ed04682abb13d94752bd44a604eec5a5bf578de2fdc6e' - '1780f4aa9e5b483a7c9ea6921504f5424007eb3bbf0ef82660bcaf942e067c5d' - 'f0ef8936532e96abc2b8158a657eb6748f4468e396368140e2410c5b114bd69f' - '354ba0dfc8985363fcccb3f561e4886707db11aedce9dfe62dd178b0ee687acb' - 'eaa7bbb8a86713f807595ad90a80346969e1f0d7d3826f1d40360d54518b97b1' - 'b1506ee10ed0c18e2a6a2cc856647512f67897b79eaa018fc4bf46ae4620d2a1' - '4bf6eb62ba85703f58bbb01e2a2e799231ee09bf936781899a909371c0f23374' - '8806664615edf5056317d922ae8aaa5526a48ff123ea1704a756bb6e772df776' - '40f9baea1875983a3d69915b05fb2fbb122e0ac27090079c41452186b48f83d5' - '46d3246dbda5ae825752ead189dec1e62c8d9c4b3b94c079025bf0768646d708' - '02b06ecf4202d6657d6ddbbc4594df8a98cdb77d4ae0d08b6c99377bbe58a3e7' - '56953242710bed28c7a92de3f7e40f27ab47d83ffce272bb5d107ac70c4deee1' - 'cd9620285ad69cc6c93d92e8070237d5f7a123b7337931adc487b1053d7b2599' - '76e6c300a2a29f56e45f7dfdadf640bb8ffa36cbe51c2c7674f32bf4e4439133') + '0e60408275c4dfd30f61fc6a6fabfa9d26e6589a05caf845d8b5eee10744cbe0' + 'd151ce001d297e067b11622f344995567333aad39fc444e0bdcd15814cdac75c' + 'ed4aae3076432cb2ed28ac0058d4fd9eea402b3ed3e75fb1863527c653089727' + 'c2e5c1f6234aa7c993a79feefc31f4a0395c2175cf2072d0abc047b4830e13aa' + 'c17f7b0a2b54f88ed66f4cf35fd59ad81749e3f51b89ed6324c3672707928e3a' + '2d75bc845525de78f73a1125258e500a46ad1129e8bd67bc5af432f4874dcd28' + 'c9eaa118300655b822f01e6379902b2ad65fa246074c1669e80c48bf1586a1a9' + '421ef29f1fd0f100d3d47b7329c6ea6d77a7164d0b6834e18512f20df499120b' + 'fd1d4c7604f58b877c2a92ea3c8fca55d13bb030dea19fb18675d053254acadb' + 'abc3c0bcc3b2f4482277053584f9262800d47644a9fd5aa9e25585346479becf' + '0ee51e05ad327bfd57c9ea574badc48a07ed364b81cb30718abacdb04a912f86' + 'a902ec0578d242bbfc9f52b644d10c5c9b9a2a7041177a1c94c2e51d1eb7d4a1' + '6dfe7895614a445ae03bc02db8081d3030c9cd81f0b678c240d699c539d293ff' + 'd255744eddcf2a4e1fc8f88e611aa97befea10aa572402866a870815d0a75b06' + 'ca47c4c1a997686f70d410846e221de857e698e02058889d04c8338bfd7850a5' + '8544821a0ad3c2757aa99662a785df6df17d6a21fd084c03cf4b73b0c4602341') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/config b/pkg/arch/kernel/config index 236d97838a..644f252ada 100644 --- a/pkg/arch/kernel/config +++ b/pkg/arch/kernel/config @@ -1,24 +1,25 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.17.1-arch1 Kernel Configuration +# Linux/x86 6.18.2-arch2 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="gcc (GCC) 15.2.1 20250813" +CONFIG_CC_VERSION_TEXT="gcc (GCC) 15.2.1 20251112" CONFIG_CC_IS_GCC=y CONFIG_GCC_VERSION=150201 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y -CONFIG_AS_VERSION=24500 +CONFIG_AS_VERSION=24501 CONFIG_LD_IS_BFD=y -CONFIG_LD_VERSION=24500 +CONFIG_LD_VERSION=24501 CONFIG_LLD_VERSION=0 -CONFIG_RUSTC_VERSION=109000 +CONFIG_RUSTC_VERSION=109200 CONFIG_RUST_IS_AVAILABLE=y -CONFIG_RUSTC_LLVM_VERSION=200108 +CONFIG_RUSTC_LLVM_VERSION=210106 CONFIG_CC_CAN_LINK=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_CC_HAS_ASSUME=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y CONFIG_CC_HAS_COUNTED_BY=y CONFIG_CC_HAS_MULTIDIMENSIONAL_NONSTRING=y @@ -27,7 +28,8 @@ CONFIG_RUSTC_HAS_COERCE_POINTEE=y CONFIG_RUSTC_HAS_SPAN_FILE=y CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES=y CONFIG_RUSTC_HAS_FILE_WITH_NUL=y -CONFIG_PAHOLE_VERSION=130 +CONFIG_RUSTC_HAS_FILE_AS_C_STR=y +CONFIG_PAHOLE_VERSION=131 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -332,8 +334,8 @@ CONFIG_PERF_EVENTS=y CONFIG_SYSTEM_DATA_VERIFICATION=y CONFIG_PROFILING=y CONFIG_RUST=y -CONFIG_RUSTC_VERSION_TEXT="rustc 1.90.0 (1159e78c4 2025-09-14) (Arch Linux rust 1:1.90.0-3)" -CONFIG_BINDGEN_VERSION_TEXT="bindgen 0.72.0" +CONFIG_RUSTC_VERSION_TEXT="rustc 1.92.0 (ded5c06cf 2025-12-08) (Arch Linux rust 1:1.92.0-1)" +CONFIG_BINDGEN_VERSION_TEXT="bindgen 0.72.1" CONFIG_TRACEPOINTS=y # @@ -349,6 +351,7 @@ CONFIG_KEXEC_SIG=y CONFIG_KEXEC_BZIMAGE_VERIFY_SIG=y CONFIG_KEXEC_JUMP=y CONFIG_KEXEC_HANDOVER=y +# CONFIG_KEXEC_HANDOVER_DEBUG is not set CONFIG_CRASH_DUMP=y CONFIG_CRASH_DM_CRYPT=y CONFIG_CRASH_DM_CRYPT_CONFIGS=y @@ -379,7 +382,6 @@ CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_AUDIT_ARCH=y CONFIG_HAVE_INTEL_TXT=y -CONFIG_X86_64_SMP=y CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_FIX_EARLYCON_MEM=y CONFIG_DYNAMIC_PHYSICAL_MASK=y @@ -390,6 +392,7 @@ CONFIG_PGTABLE_LEVELS=5 # CONFIG_SMP=y CONFIG_X86_X2APIC=y +CONFIG_AMD_SECURE_AVIC=y CONFIG_X86_POSTED_MSI=y CONFIG_X86_MPPARSE=y CONFIG_X86_CPU_RESCTRL=y @@ -415,7 +418,6 @@ CONFIG_XEN_PV_DOM0=y CONFIG_XEN_PVHVM=y CONFIG_XEN_PVHVM_SMP=y CONFIG_XEN_PVHVM_GUEST=y -CONFIG_XEN_SAVE_RESTORE=y # CONFIG_XEN_DEBUG_FS is not set CONFIG_XEN_PVH=y CONFIG_XEN_DOM0=y @@ -427,6 +429,7 @@ CONFIG_PARAVIRT_TIME_ACCOUNTING=y CONFIG_PARAVIRT_CLOCK=y CONFIG_JAILHOUSE_GUEST=y CONFIG_ACRN_GUEST=y +CONFIG_BHYVE_GUEST=y CONFIG_INTEL_TDX_GUEST=y CONFIG_CC_HAS_MARCH_NATIVE=y # CONFIG_X86_NATIVE_CPU is not set @@ -456,9 +459,6 @@ CONFIG_NR_CPUS_RANGE_BEGIN=8192 CONFIG_NR_CPUS_RANGE_END=8192 CONFIG_NR_CPUS_DEFAULT=8192 CONFIG_NR_CPUS=8192 -CONFIG_SCHED_CLUSTER=y -CONFIG_SCHED_SMT=y -CONFIG_SCHED_MC=y CONFIG_SCHED_MC_PRIO=y CONFIG_X86_LOCAL_APIC=y CONFIG_ACPI_MADT_WAKEUP=y @@ -488,6 +488,7 @@ CONFIG_X86_VSYSCALL_EMULATION=y CONFIG_X86_IOPL_IOPERM=y CONFIG_MICROCODE=y # CONFIG_MICROCODE_LATE_LOADING is not set +# CONFIG_MICROCODE_DBG is not set CONFIG_X86_MSR=y CONFIG_X86_CPUID=y CONFIG_X86_DIRECT_GBPAGES=y @@ -523,6 +524,7 @@ CONFIG_ARCH_PKEY_BITS=4 CONFIG_X86_INTEL_TSX_MODE_AUTO=y CONFIG_X86_SGX=y CONFIG_X86_USER_SHADOW_STACK=y +CONFIG_INTEL_TDX_HOST=y CONFIG_EFI=y CONFIG_EFI_STUB=y CONFIG_EFI_HANDOVER_PROTOCOL=y @@ -810,22 +812,23 @@ CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY=y CONFIG_KVM_COMPAT=y CONFIG_HAVE_KVM_IRQ_BYPASS=m CONFIG_HAVE_KVM_NO_POLL=y -CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRT_XFER_TO_GUEST_WORK=y CONFIG_HAVE_KVM_PM_NOTIFIER=y CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y CONFIG_KVM_GENERIC_MMU_NOTIFIER=y CONFIG_KVM_ELIDE_TLB_FLUSH_IF_YOUNG=y CONFIG_KVM_MMU_LOCKLESS_AGING=y CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES=y -CONFIG_KVM_PRIVATE_MEM=y -CONFIG_KVM_GENERIC_PRIVATE_MEM=y +CONFIG_KVM_GUEST_MEMFD=y CONFIG_HAVE_KVM_ARCH_GMEM_PREPARE=y CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE=y +CONFIG_HAVE_KVM_ARCH_GMEM_POPULATE=y CONFIG_VIRTUALIZATION=y CONFIG_KVM_X86=m CONFIG_KVM=m CONFIG_KVM_INTEL=m CONFIG_X86_SGX_KVM=y +CONFIG_KVM_INTEL_TDX=y CONFIG_KVM_AMD=m CONFIG_KVM_AMD_SEV=y CONFIG_KVM_IOAPIC=y @@ -851,10 +854,6 @@ CONFIG_X86_DISABLED_FEATURE_K6_MTRR=y CONFIG_X86_DISABLED_FEATURE_CYRIX_ARR=y CONFIG_X86_DISABLED_FEATURE_CENTAUR_MCR=y CONFIG_X86_DISABLED_FEATURE_LAM=y -CONFIG_AS_AVX512=y -CONFIG_AS_GFNI=y -CONFIG_AS_VAES=y -CONFIG_AS_VPCLMULQDQ=y CONFIG_AS_WRUSS=y CONFIG_ARCH_CONFIGURES_CPU_MITIGATIONS=y CONFIG_ARCH_HAS_DMA_OPS=y @@ -863,6 +862,12 @@ CONFIG_ARCH_HAS_DMA_OPS=y # General architecture-dependent options # CONFIG_HOTPLUG_SMT=y +CONFIG_ARCH_SUPPORTS_SCHED_SMT=y +CONFIG_ARCH_SUPPORTS_SCHED_CLUSTER=y +CONFIG_ARCH_SUPPORTS_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_SCHED_CLUSTER=y +CONFIG_SCHED_MC=y CONFIG_HOTPLUG_CORE_SYNC=y CONFIG_HOTPLUG_CORE_SYNC_DEAD=y CONFIG_HOTPLUG_CORE_SYNC_FULL=y @@ -945,7 +950,7 @@ CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y CONFIG_LTO_NONE=y CONFIG_ARCH_SUPPORTS_AUTOFDO_CLANG=y CONFIG_ARCH_SUPPORTS_PROPELLER_CLANG=y -CONFIG_ARCH_SUPPORTS_CFI_CLANG=y +CONFIG_ARCH_SUPPORTS_CFI=y CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y CONFIG_HAVE_CONTEXT_TRACKING_USER=y CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK=y @@ -1020,6 +1025,7 @@ CONFIG_ARCH_HAS_HW_PTE_YOUNG=y CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y CONFIG_ARCH_HAS_KERNEL_FPU_SUPPORT=y CONFIG_ARCH_VMLINUX_NEEDS_RELOCS=y +CONFIG_HAVE_GENERIC_TIF_BITS=y # # GCOV-based kernel profiling @@ -1165,7 +1171,6 @@ CONFIG_COREDUMP=y # # Memory Management options # -CONFIG_ZPOOL=y CONFIG_SWAP=y CONFIG_ZSWAP=y CONFIG_ZSWAP_DEFAULT_ON=y @@ -1177,11 +1182,18 @@ CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y # CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4HC is not set CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y CONFIG_ZSWAP_COMPRESSOR_DEFAULT="zstd" -CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC=y -CONFIG_ZSWAP_ZPOOL_DEFAULT="zsmalloc" CONFIG_ZSMALLOC=y + +# +# Zsmalloc allocator options +# + +# +# Zsmalloc is a common backend allocator for zswap & zram +# CONFIG_ZSMALLOC_STAT=y CONFIG_ZSMALLOC_CHAIN_SIZE=8 +# end of Zsmalloc allocator options # # Slab allocator options @@ -1209,6 +1221,7 @@ CONFIG_ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP=y CONFIG_ARCH_WANT_HUGETLB_VMEMMAP_PREINIT=y CONFIG_HAVE_GUP_FAST=y CONFIG_MEMBLOCK_KHO_SCRATCH=y +CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_NUMA_KEEP_MEMINFO=y CONFIG_MEMORY_ISOLATION=y CONFIG_EXCLUSIVE_SYSTEM_RAM=y @@ -1246,6 +1259,7 @@ CONFIG_MEMORY_FAILURE=y CONFIG_HWPOISON_INJECT=m CONFIG_ARCH_WANT_GENERAL_HUGETLB=y CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_PERSISTENT_HUGE_ZERO_FOLIO=y CONFIG_MM_ID=y CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y @@ -1256,6 +1270,7 @@ CONFIG_READ_ONLY_THP_FOR_FS=y # CONFIG_NO_PAGE_MAPCOUNT is not set CONFIG_PAGE_MAPCOUNT=y CONFIG_PGTABLE_HAS_HUGE_LEAVES=y +CONFIG_HAVE_GIGANTIC_FOLIOS=y CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP=y CONFIG_ARCH_SUPPORTS_PMD_PFNMAP=y CONFIG_ARCH_SUPPORTS_PUD_PFNMAP=y @@ -1312,6 +1327,7 @@ CONFIG_NUMA_MEMBLKS=y CONFIG_ARCH_HAS_USER_SHADOW_STACK=y CONFIG_ARCH_SUPPORTS_PT_RECLAIM=y CONFIG_PT_RECLAIM=y +CONFIG_FIND_NORMAL_PAGE=y # # Data Access Monitoring @@ -1344,6 +1360,7 @@ CONFIG_NET_CRC32C=y # CONFIG_PACKET=y CONFIG_PACKET_DIAG=m +CONFIG_INET_PSP=y CONFIG_UNIX=y CONFIG_AF_UNIX_OOB=y CONFIG_UNIX_DIAG=m @@ -1368,7 +1385,8 @@ CONFIG_XFRM_IPTFS=m CONFIG_XFRM_ESPINTCP=y CONFIG_SMC=m CONFIG_SMC_DIAG=m -CONFIG_SMC_LO=y +CONFIG_DIBS=m +CONFIG_DIBS_LO=y CONFIG_XDP_SOCKETS=y CONFIG_XDP_SOCKETS_DIAG=m CONFIG_NET_HANDSHAKE=y @@ -1832,11 +1850,8 @@ CONFIG_BRIDGE_EBT_LOG=m CONFIG_BRIDGE_EBT_NFLOG=m CONFIG_IP_SCTP=m # CONFIG_SCTP_DBG_OBJCNT is not set -# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set -CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y +CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA256=y # CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set -CONFIG_SCTP_COOKIE_HMAC_MD5=y -CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_INET_SCTP_DIAG=m CONFIG_RDS=m CONFIG_RDS_RDMA=m @@ -2026,7 +2041,6 @@ CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_BATMAN_V=y CONFIG_BATMAN_ADV_BLA=y CONFIG_BATMAN_ADV_DAT=y -CONFIG_BATMAN_ADV_NC=y CONFIG_BATMAN_ADV_MCAST=y # CONFIG_BATMAN_ADV_DEBUG is not set # CONFIG_BATMAN_ADV_TRACING is not set @@ -2318,6 +2332,7 @@ CONFIG_PCI_PF_STUB=m CONFIG_XEN_PCIDEV_FRONTEND=m CONFIG_PCI_ATS=y CONFIG_PCI_DOE=y +CONFIG_PCI_ECAM=y CONFIG_PCI_LOCKLESS_CONFIG=y CONFIG_PCI_IOV=y CONFIG_PCI_NPEM=y @@ -2341,6 +2356,7 @@ CONFIG_HOTPLUG_PCI_SHPC=y # # PCI controller drivers # +CONFIG_PCI_HOST_COMMON=y CONFIG_VMD=m CONFIG_PCI_HYPERV_INTERFACE=m @@ -2726,6 +2742,7 @@ CONFIG_PNP_DEBUG_MESSAGES=y CONFIG_PNPACPI=y CONFIG_BLK_DEV=y CONFIG_BLK_DEV_NULL_BLK=m +# CONFIG_BLK_DEV_RUST_NULL is not set CONFIG_BLK_DEV_FD=m # CONFIG_BLK_DEV_FD_RAWCMD is not set CONFIG_CDROM=m @@ -2761,7 +2778,6 @@ CONFIG_ATA_OVER_ETH=m CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_BLKDEV_BACKEND=m CONFIG_VIRTIO_BLK=y -# CONFIG_BLK_DEV_RUST_NULL is not set CONFIG_BLK_DEV_RBD=m CONFIG_BLK_DEV_UBLK=m CONFIG_BLKDEV_UBLK_LEGACY_OPCODES=y @@ -2849,6 +2865,7 @@ CONFIG_EEPROM_93CX6=m # CONFIG_EEPROM_93XX46 is not set CONFIG_EEPROM_IDT_89HPESX=m CONFIG_EEPROM_EE1004=m +CONFIG_EEPROM_M24LR=m # end of EEPROM support CONFIG_CB710_CORE=m @@ -2862,6 +2879,7 @@ CONFIG_INTEL_MEI_TXE=m CONFIG_INTEL_MEI_GSC=m CONFIG_INTEL_MEI_VSC_HW=m CONFIG_INTEL_MEI_VSC=m +CONFIG_INTEL_MEI_LB=m CONFIG_INTEL_MEI_HDCP=m CONFIG_INTEL_MEI_PXP=m CONFIG_INTEL_MEI_GSC_PROXY=m @@ -2880,8 +2898,6 @@ CONFIG_PVPANIC_PCI=m CONFIG_GP_PCI1XXXX=m CONFIG_KEBA_CP500=m CONFIG_KEBA_LAN9252=m -CONFIG_AMD_SBRMI_I2C=m -CONFIG_AMD_SBRMI_HWMON=y # end of Misc devices # @@ -3154,6 +3170,8 @@ CONFIG_ATA_GENERIC=m CONFIG_PATA_LEGACY=m CONFIG_MD=y CONFIG_BLK_DEV_MD=m +CONFIG_MD_BITMAP=y +CONFIG_MD_LLBITMAP=y CONFIG_MD_BITMAP_FILE=y CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m @@ -3206,6 +3224,7 @@ CONFIG_DM_INTEGRITY=m CONFIG_DM_ZONED=m CONFIG_DM_AUDIT=y CONFIG_DM_VDO=m +CONFIG_DM_PCACHE=m CONFIG_TARGET_CORE=m CONFIG_TCM_IBLOCK=m CONFIG_TCM_FILEIO=m @@ -3348,6 +3367,7 @@ CONFIG_NET_DSA_XRS700X=m CONFIG_NET_DSA_XRS700X_I2C=m CONFIG_NET_DSA_XRS700X_MDIO=m CONFIG_NET_DSA_REALTEK=m +CONFIG_NET_DSA_KS8995=m CONFIG_NET_DSA_SMSC_LAN9303=m CONFIG_NET_DSA_SMSC_LAN9303_I2C=m CONFIG_NET_DSA_SMSC_LAN9303_MDIO=m @@ -3489,8 +3509,10 @@ CONFIG_HINIC3=m CONFIG_NET_VENDOR_I825XX=y CONFIG_NET_VENDOR_INTEL=y CONFIG_LIBETH=m +CONFIG_LIBETH_XDP=m CONFIG_LIBIE=m CONFIG_LIBIE_ADMINQ=m +CONFIG_LIBIE_FWLOG=m CONFIG_E100=m CONFIG_E1000=m CONFIG_E1000E=m @@ -3561,6 +3583,7 @@ CONFIG_MLX5_HW_STEERING=y CONFIG_MLX5_SF=y CONFIG_MLX5_SF_MANAGER=y CONFIG_MLX5_DPLL=m +CONFIG_MLX5_EN_PSP=y CONFIG_MLXSW_CORE=m CONFIG_MLXSW_CORE_HWMON=y CONFIG_MLXSW_CORE_THERMAL=y @@ -3732,6 +3755,7 @@ CONFIG_FDDI=m CONFIG_DEFXX=m CONFIG_SKFP=m # CONFIG_HIPPI is not set +CONFIG_MDIO_BUS=m CONFIG_PHYLINK=m CONFIG_PHYLIB=m CONFIG_SWPHY=y @@ -3807,10 +3831,10 @@ CONFIG_DP83TD510_PHY=m CONFIG_DP83TG720_PHY=m CONFIG_VITESSE_PHY=m CONFIG_XILINX_GMII2RGMII=m -CONFIG_MICREL_KS8995MA=m CONFIG_PSE_CONTROLLER=y CONFIG_PSE_REGULATOR=m CONFIG_PSE_PD692X0=m +CONFIG_PSE_SI3474=m CONFIG_PSE_TPS23881=m CONFIG_CAN_DEV=m CONFIG_CAN_VCAN=m @@ -3871,6 +3895,7 @@ CONFIG_CAN_F81604=m CONFIG_CAN_GS_USB=m CONFIG_CAN_KVASER_USB=m CONFIG_CAN_MCBA_USB=m +CONFIG_CAN_NCT6694=m CONFIG_CAN_PEAK_USB=m CONFIG_CAN_UCAN=m # end of CAN USB interfaces @@ -3885,7 +3910,6 @@ CONFIG_MCTP_TRANSPORT_I2C=m CONFIG_MCTP_TRANSPORT_USB=m # end of MCTP Device Drivers -CONFIG_MDIO_BUS=m CONFIG_FWNODE_MDIO=m CONFIG_ACPI_MDIO=m CONFIG_MDIO_BITBANG=m @@ -4421,12 +4445,12 @@ CONFIG_KEYBOARD_DLINK_DIR685=m CONFIG_KEYBOARD_LKKBD=m CONFIG_KEYBOARD_GPIO=m CONFIG_KEYBOARD_GPIO_POLLED=m -CONFIG_KEYBOARD_TCA6416=m CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_LM8323=m CONFIG_KEYBOARD_LM8333=m CONFIG_KEYBOARD_MAX7359=m +CONFIG_KEYBOARD_MAX7360=m CONFIG_KEYBOARD_MPR121=m CONFIG_KEYBOARD_NEWTON=m CONFIG_KEYBOARD_OPENCORES=m @@ -4548,8 +4572,10 @@ CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE=m CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C=m CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI=m CONFIG_TOUCHSCREEN_HIDEEP=m +CONFIG_TOUCHSCREEN_HIMAX_HX852X=m CONFIG_TOUCHSCREEN_HYCON_HY46XX=m CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX=m +CONFIG_TOUCHSCREEN_HYNITRON_CST816X=m CONFIG_TOUCHSCREEN_ILI210X=m CONFIG_TOUCHSCREEN_ILITEK=m CONFIG_TOUCHSCREEN_S6SY761=m @@ -4631,10 +4657,12 @@ CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m CONFIG_INPUT_ARIZONA_HAPTICS=m CONFIG_INPUT_ATC260X_ONKEY=m +CONFIG_INPUT_AW86927=m CONFIG_INPUT_BMA150=m # CONFIG_INPUT_CS40L50_VIBRA is not set CONFIG_INPUT_E3X0_BUTTON=m CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_MAX7360_ROTARY=m CONFIG_INPUT_MAX77693_HAPTIC=m CONFIG_INPUT_MAX8925_ONKEY=m CONFIG_INPUT_MAX8997_HAPTIC=m @@ -4653,6 +4681,7 @@ CONFIG_INPUT_YEALINK=m CONFIG_INPUT_CM109=m CONFIG_INPUT_REGULATOR_HAPTIC=m CONFIG_INPUT_RETU_PWRBUTTON=m +CONFIG_INPUT_TPS6594_PWRBUTTON=m CONFIG_INPUT_AXP20X_PEK=m CONFIG_INPUT_TWL4030_PWRBUTTON=m CONFIG_INPUT_TWL4030_VIBRA=m @@ -4970,6 +4999,8 @@ CONFIG_I2C_XILINX=m CONFIG_I2C_DIOLAN_U2C=m CONFIG_I2C_DLN2=m CONFIG_I2C_LJCA=m +CONFIG_I2C_NCT6694=m +CONFIG_I2C_USBIO=m CONFIG_I2C_CP2615=m CONFIG_I2C_PARPORT=m CONFIG_I2C_PCI1XXXX=m @@ -5036,6 +5067,7 @@ CONFIG_SPI_PXA2XX_PCI=m CONFIG_SPI_SC18IS602=m CONFIG_SPI_SIFIVE=m CONFIG_SPI_MXIC=m +CONFIG_SPI_VIRTIO=m CONFIG_SPI_XCOMM=m CONFIG_SPI_XILINX=m CONFIG_SPI_ZYNQMP_GQSPI=m @@ -5094,6 +5126,7 @@ CONFIG_PTP_1588_CLOCK_MOCK=m CONFIG_PTP_1588_CLOCK_VMW=m CONFIG_PTP_1588_CLOCK_OCP=m CONFIG_PTP_DFL_TOD=m +CONFIG_PTP_NETC_V4_TIMER=m # end of PTP clock support # @@ -5106,7 +5139,9 @@ CONFIG_ZL3073X_SPI=m # end of DPLL device support CONFIG_PINCTRL=y +CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_PINMUX=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y CONFIG_PINCONF=y CONFIG_GENERIC_PINCONF=y # CONFIG_DEBUG_PINCTRL is not set @@ -5114,10 +5149,12 @@ CONFIG_PINCTRL_AMD=y CONFIG_PINCTRL_AMDISP=m CONFIG_PINCTRL_CY8C95X0=m CONFIG_PINCTRL_DA9062=m +CONFIG_PINCTRL_MAX7360=m CONFIG_PINCTRL_MCP23S08_I2C=m CONFIG_PINCTRL_MCP23S08_SPI=m CONFIG_PINCTRL_MCP23S08=m CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_UPBOARD=m CONFIG_PINCTRL_CS42L43=m CONFIG_PINCTRL_MADERA=m CONFIG_PINCTRL_CS47L15=y @@ -5235,6 +5272,8 @@ CONFIG_GPIO_LJCA=m CONFIG_GPIO_LP3943=m CONFIG_GPIO_LP873X=m CONFIG_GPIO_MADERA=m +CONFIG_GPIO_MAX7360=m +CONFIG_GPIO_NCT6694=m CONFIG_GPIO_PALMAS=m CONFIG_GPIO_RC5T583=y CONFIG_GPIO_TPS65086=m @@ -5277,6 +5316,7 @@ CONFIG_GPIO_XRA1403=m # CONFIG_GPIO_VIPERBOARD=m CONFIG_GPIO_MPSSE=m +CONFIG_GPIO_USBIO=m # end of USB GPIO expanders # @@ -5344,6 +5384,7 @@ CONFIG_POWER_SEQUENCING=m CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set CONFIG_POWER_SUPPLY_HWMON=y +CONFIG_ADC_BATTERY_HELPER=m CONFIG_GENERIC_ADC_BATTERY=m CONFIG_IP5XXX_POWER=m CONFIG_MAX8925_POWER=m @@ -5360,6 +5401,7 @@ CONFIG_BATTERY_DS2780=m CONFIG_BATTERY_DS2781=m CONFIG_BATTERY_DS2782=m # CONFIG_BATTERY_SAMSUNG_SDI is not set +CONFIG_BATTERY_INTEL_DC_TI=m CONFIG_BATTERY_SBS=m CONFIG_CHARGER_SBS=m CONFIG_MANAGER_SBS=m @@ -5408,6 +5450,7 @@ CONFIG_CHARGER_BQ24190=m CONFIG_CHARGER_BQ24257=m CONFIG_CHARGER_BQ24735=m CONFIG_CHARGER_BQ2515X=m +CONFIG_CHARGER_BQ257XX=m CONFIG_CHARGER_BQ25890=m CONFIG_CHARGER_BQ25980=m CONFIG_CHARGER_BQ256XX=m @@ -5492,6 +5535,7 @@ CONFIG_SENSORS_FTSTEUTATES=m CONFIG_SENSORS_GIGABYTE_WATERFORCE=m CONFIG_SENSORS_GL518SM=m CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_GPD=m CONFIG_SENSORS_G760A=m CONFIG_SENSORS_G762=m CONFIG_SENSORS_HIH6130=m @@ -5568,6 +5612,7 @@ CONFIG_SENSORS_PC87360=m CONFIG_SENSORS_PC87427=m CONFIG_SENSORS_NTC_THERMISTOR=m CONFIG_SENSORS_NCT6683=m +CONFIG_SENSORS_NCT6694=m CONFIG_SENSORS_NCT6775_CORE=m CONFIG_SENSORS_NCT6775=m CONFIG_SENSORS_NCT6775_I2C=m @@ -5621,8 +5666,10 @@ CONFIG_SENSORS_MAX31785=m CONFIG_SENSORS_MAX34440=m CONFIG_SENSORS_MAX8688=m CONFIG_SENSORS_MP2856=m +CONFIG_SENSORS_MP2869=m CONFIG_SENSORS_MP2888=m CONFIG_SENSORS_MP2891=m +CONFIG_SENSORS_MP29502=m CONFIG_SENSORS_MP2975=m CONFIG_SENSORS_MP2993=m CONFIG_SENSORS_MP2975_REGULATOR=y @@ -5816,6 +5863,7 @@ CONFIG_CADENCE_WATCHDOG=m CONFIG_DW_WATCHDOG=m CONFIG_TWL4030_WATCHDOG=m CONFIG_MAX63XX_WATCHDOG=m +CONFIG_NCT6694_WATCHDOG=m CONFIG_RETU_WATCHDOG=m CONFIG_ACQUIRE_WDT=m CONFIG_ADVANTECH_WDT=m @@ -5969,6 +6017,7 @@ CONFIG_MFD_MT6360=m CONFIG_MFD_MT6370=m CONFIG_MFD_MT6397=m CONFIG_MFD_MENF21BMC=m +CONFIG_MFD_NCT6694=m CONFIG_MFD_OCELOT=m CONFIG_EZX_PCAP=y CONFIG_MFD_VIPERBOARD=m @@ -5988,6 +6037,7 @@ CONFIG_MFD_SYSCON=y CONFIG_MFD_LP3943=m CONFIG_MFD_LP8788=y CONFIG_MFD_TI_LMU=m +CONFIG_MFD_BQ257XX=m CONFIG_MFD_PALMAS=m CONFIG_TPS6105X=m CONFIG_TPS65010=m @@ -6034,6 +6084,7 @@ CONFIG_MFD_INTEL_M10_BMC_SPI=m CONFIG_MFD_INTEL_M10_BMC_PMCI=m CONFIG_MFD_QNAP_MCU=m CONFIG_MFD_UPBOARD_FPGA=m +CONFIG_MFD_MAX7360=m # end of Multifunction device drivers CONFIG_REGULATOR=y @@ -6057,6 +6108,7 @@ CONFIG_REGULATOR_AW37503=m CONFIG_REGULATOR_AXP20X=m CONFIG_REGULATOR_BCM590XX=m CONFIG_REGULATOR_BD9571MWV=m +CONFIG_REGULATOR_BQ257XX=m CONFIG_REGULATOR_DA903X=m CONFIG_REGULATOR_DA9052=m CONFIG_REGULATOR_DA9055=m @@ -6092,6 +6144,7 @@ CONFIG_REGULATOR_MAX20086=m CONFIG_REGULATOR_MAX20411=m CONFIG_REGULATOR_MAX77693=m CONFIG_REGULATOR_MAX77826=m +CONFIG_REGULATOR_MAX77838=m CONFIG_REGULATOR_MC13XXX_CORE=m CONFIG_REGULATOR_MC13783=m CONFIG_REGULATOR_MC13892=m @@ -6110,6 +6163,7 @@ CONFIG_REGULATOR_PALMAS=m CONFIG_REGULATOR_PCA9450=m CONFIG_REGULATOR_PF9453=m CONFIG_REGULATOR_PCAP=m +CONFIG_REGULATOR_PF0900=m CONFIG_REGULATOR_PV88060=m CONFIG_REGULATOR_PV88080=m CONFIG_REGULATOR_PV88090=m @@ -6504,7 +6558,6 @@ CONFIG_RADIO_SI476X=m CONFIG_RADIO_TEA575X=m CONFIG_RADIO_TEA5764=m CONFIG_RADIO_TEF6862=m -CONFIG_RADIO_WL1273=m CONFIG_USB_DSBR=m CONFIG_USB_KEENE=m CONFIG_USB_MA901=m @@ -6691,6 +6744,7 @@ CONFIG_VIDEO_CCS_PLL=m CONFIG_VIDEO_ALVIUM_CSI2=m CONFIG_VIDEO_AR0521=m CONFIG_VIDEO_GC0308=m +CONFIG_VIDEO_GC0310=m CONFIG_VIDEO_GC05A2=m CONFIG_VIDEO_GC08A3=m CONFIG_VIDEO_GC2145=m @@ -6714,9 +6768,9 @@ CONFIG_VIDEO_MT9M114=m CONFIG_VIDEO_MT9P031=m CONFIG_VIDEO_MT9T112=m CONFIG_VIDEO_MT9V011=m -CONFIG_VIDEO_MT9V032=m CONFIG_VIDEO_MT9V111=m CONFIG_VIDEO_OG01A1B=m +CONFIG_VIDEO_OG0VE1B=m CONFIG_VIDEO_OV01A10=m CONFIG_VIDEO_OV02A10=m CONFIG_VIDEO_OV02E10=m @@ -6729,6 +6783,7 @@ CONFIG_VIDEO_OV2640=m CONFIG_VIDEO_OV2659=m CONFIG_VIDEO_OV2680=m CONFIG_VIDEO_OV2685=m +CONFIG_VIDEO_OV2735=m CONFIG_VIDEO_OV2740=m CONFIG_VIDEO_OV4689=m CONFIG_VIDEO_OV5647=m @@ -6737,8 +6792,8 @@ CONFIG_VIDEO_OV5670=m CONFIG_VIDEO_OV5675=m CONFIG_VIDEO_OV5693=m CONFIG_VIDEO_OV5695=m +CONFIG_VIDEO_OV6211=m CONFIG_VIDEO_OV64A40=m -CONFIG_VIDEO_OV6650=m CONFIG_VIDEO_OV7251=m CONFIG_VIDEO_OV7640=m CONFIG_VIDEO_OV7670=m @@ -7158,7 +7213,6 @@ CONFIG_NOUVEAU_DEBUG_DEFAULT=3 # CONFIG_NOUVEAU_DEBUG_PUSH is not set CONFIG_DRM_NOUVEAU_BACKLIGHT=y CONFIG_DRM_NOUVEAU_SVM=y -CONFIG_DRM_NOUVEAU_GSP_DEFAULT=y CONFIG_DRM_NOUVEAU_CH7006=m CONFIG_DRM_NOUVEAU_SIL164=m # CONFIG_DRM_NOVA is not set @@ -7235,6 +7289,7 @@ CONFIG_DRM_BOCHS=m CONFIG_DRM_CIRRUS_QEMU=m CONFIG_DRM_GM12U320=m CONFIG_DRM_PANEL_MIPI_DBI=m +CONFIG_DRM_PIXPAPER=m CONFIG_TINYDRM_HX8357D=m CONFIG_TINYDRM_ILI9163=m CONFIG_TINYDRM_ILI9225=m @@ -7406,6 +7461,7 @@ CONFIG_TRACE_GPU_MEM=y CONFIG_DRM_ACCEL=y CONFIG_DRM_ACCEL_AMDXDNA=m CONFIG_DRM_ACCEL_HABANALABS=m +CONFIG_HL_HLDIO=y CONFIG_DRM_ACCEL_IVPU=m # CONFIG_DRM_ACCEL_IVPU_DEBUG is not set CONFIG_DRM_ACCEL_QAIC=m @@ -7635,6 +7691,7 @@ CONFIG_SND_USB_USX2Y=m CONFIG_SND_USB_CAIAQ=m CONFIG_SND_USB_CAIAQ_INPUT=y CONFIG_SND_USB_US122L=m +CONFIG_SND_USB_US144MKII=m CONFIG_SND_USB_6FIRE=m CONFIG_SND_USB_HIFACE=m CONFIG_SND_BCD2000=m @@ -8101,6 +8158,8 @@ CONFIG_SND_SOC_ES8328_I2C=m CONFIG_SND_SOC_ES8328_SPI=m CONFIG_SND_SOC_ES8375=m CONFIG_SND_SOC_ES8389=m +CONFIG_SND_SOC_FS_AMP_LIB=m +CONFIG_SND_SOC_FS210X=m CONFIG_SND_SOC_GTM601=m CONFIG_SND_SOC_HDAC_HDA=m CONFIG_SND_SOC_HDA=m @@ -8123,6 +8182,7 @@ CONFIG_SND_SOC_MAX98396=m CONFIG_SND_SOC_MAX9860=m CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m CONFIG_SND_SOC_PCM1681=m +CONFIG_SND_SOC_PCM1754=m CONFIG_SND_SOC_PCM1789=m CONFIG_SND_SOC_PCM1789_I2C=m CONFIG_SND_SOC_PCM179X=m @@ -8143,6 +8203,8 @@ CONFIG_SND_SOC_PCM512x_I2C=m CONFIG_SND_SOC_PCM512x_SPI=m CONFIG_SND_SOC_PCM6240=m CONFIG_SND_SOC_PEB2466=m +CONFIG_SND_SOC_PM4125=m +CONFIG_SND_SOC_PM4125_SDW=m CONFIG_SND_SOC_RL6231=m CONFIG_SND_SOC_RT_SDW_COMMON=m CONFIG_SND_SOC_RL6347A=m @@ -8223,6 +8285,7 @@ CONFIG_SND_SOC_TAS2781_COMLIB=m CONFIG_SND_SOC_TAS2781_COMLIB_I2C=m CONFIG_SND_SOC_TAS2781_FMWLIB=m CONFIG_SND_SOC_TAS2781_I2C=m +CONFIG_SND_SOC_TAS2783_SDW=m CONFIG_SND_SOC_TAS5086=m CONFIG_SND_SOC_TAS571X=m CONFIG_SND_SOC_TAS5720=m @@ -8249,6 +8312,7 @@ CONFIG_SND_SOC_TSCS454=m CONFIG_SND_SOC_UDA1334=m CONFIG_SND_SOC_UDA1342=m CONFIG_SND_SOC_WCD_CLASSH=m +CONFIG_SND_SOC_WCD_COMMON=m CONFIG_SND_SOC_WCD9335=m CONFIG_SND_SOC_WCD_MBHC=m CONFIG_SND_SOC_WCD934X=m @@ -8298,6 +8362,7 @@ CONFIG_SND_SOC_MT6357=m CONFIG_SND_SOC_MT6358=m CONFIG_SND_SOC_MT6660=m CONFIG_SND_SOC_NAU8315=m +CONFIG_SND_SOC_NAU8325=m CONFIG_SND_SOC_NAU8540=m CONFIG_SND_SOC_NAU8810=m CONFIG_SND_SOC_NAU8821=m @@ -8336,6 +8401,7 @@ CONFIG_HID_BATTERY_STRENGTH=y CONFIG_HIDRAW=y CONFIG_UHID=m CONFIG_HID_GENERIC=y +CONFIG_HID_HAPTIC=y # # Special HID drivers @@ -8767,6 +8833,7 @@ CONFIG_USB_IDMOUSE=m CONFIG_USB_APPLEDISPLAY=m CONFIG_APPLE_MFI_FASTCHARGE=m CONFIG_USB_LJCA=m +CONFIG_USB_USBIO=m CONFIG_USB_SISUSBVGA=m CONFIG_USB_LD=m CONFIG_USB_TRANCEVIBRATOR=m @@ -9165,6 +9232,7 @@ CONFIG_INFINIBAND_ERDMA=m CONFIG_INFINIBAND_HFI1=m # CONFIG_HFI1_DEBUG_SDMA_ORDER is not set # CONFIG_SDMA_VERBOSITY is not set +CONFIG_INFINIBAND_IONIC=m CONFIG_INFINIBAND_IRDMA=m CONFIG_MANA_INFINIBAND=m CONFIG_MLX4_INFINIBAND=m @@ -9255,6 +9323,7 @@ CONFIG_RTC_DRV_MAX8925=m CONFIG_RTC_DRV_MAX8998=m CONFIG_RTC_DRV_MAX8997=m CONFIG_RTC_DRV_MAX31335=m +CONFIG_RTC_DRV_NCT6694=m CONFIG_RTC_DRV_RS5C372=m CONFIG_RTC_DRV_ISL1208=m CONFIG_RTC_DRV_ISL12022=m @@ -9349,13 +9418,13 @@ CONFIG_RTC_DRV_FTRTC010=m CONFIG_RTC_DRV_PCAP=m CONFIG_RTC_DRV_MC13XXX=m CONFIG_RTC_DRV_MT6397=m +CONFIG_RTC_DRV_GOLDFISH=m +CONFIG_RTC_DRV_WILCO_EC=m # # HID Sensor RTC drivers # CONFIG_RTC_DRV_HID_SENSOR_TIME=m -CONFIG_RTC_DRV_GOLDFISH=m -CONFIG_RTC_DRV_WILCO_EC=m CONFIG_DMADEVICES=y # CONFIG_DMADEVICES_DEBUG is not set @@ -9511,11 +9580,12 @@ CONFIG_VHOST_ENABLE_FORK_OWNER_CONTROL=y # # Microsoft Hyper-V guest support # -CONFIG_HYPERV=m +CONFIG_HYPERV=y # CONFIG_HYPERV_VTL_MODE is not set CONFIG_HYPERV_TIMER=y CONFIG_HYPERV_UTILS=m CONFIG_HYPERV_BALLOON=m +CONFIG_HYPERV_VMBUS=m CONFIG_MSHV_ROOT=m # end of Microsoft Hyper-V guest support @@ -9620,7 +9690,6 @@ CONFIG_VIDEO_INTEL_IPU7=m CONFIG_MOST_COMPONENTS=m CONFIG_MOST_NET=m CONFIG_MOST_VIDEO=m -CONFIG_MOST_I2C=m # CONFIG_VME_BUS is not set CONFIG_GPIB=m CONFIG_GPIB_COMMON=m @@ -9696,6 +9765,7 @@ CONFIG_HUAWEI_WMI=m CONFIG_MXM_WMI=m CONFIG_NVIDIA_WMI_EC_BACKLIGHT=m CONFIG_XIAOMI_WMI=m +CONFIG_REDMI_WMI=m CONFIG_GIGABYTE_WMI=m CONFIG_ACERHDF=m CONFIG_ACER_WIRELESS=m @@ -10078,6 +10148,7 @@ CONFIG_EXTCON_MAX3355=m CONFIG_EXTCON_MAX77693=m CONFIG_EXTCON_MAX77843=m CONFIG_EXTCON_MAX8997=m +CONFIG_EXTCON_MAX14526=m CONFIG_EXTCON_PALMAS=m CONFIG_EXTCON_PTN5150=m CONFIG_EXTCON_RT8973A=m @@ -10215,6 +10286,7 @@ CONFIG_AD7944=m CONFIG_AD7949=m CONFIG_AD799X=m CONFIG_AD9467=m +CONFIG_ADE9000=m CONFIG_AXP20X_ADC=m CONFIG_AXP288_ADC=m CONFIG_CC10001_ADC=m @@ -10225,6 +10297,7 @@ CONFIG_GEHC_PMC_ADC=m CONFIG_HI8435=m CONFIG_HX711=m CONFIG_INA2XX_ADC=m +CONFIG_INTEL_DC_TI_ADC=m CONFIG_INTEL_MRFLD_ADC=m CONFIG_LP8788_ADC=m CONFIG_LTC2309=m @@ -10256,6 +10329,7 @@ CONFIG_NCT7201=m CONFIG_PAC1921=m CONFIG_PAC1934=m CONFIG_PALMAS_GPADC=m +CONFIG_ROHM_BD79112=m CONFIG_ROHM_BD79124=m CONFIG_RICHTEK_RTQ6056=m CONFIG_SD_ADC_MODULATOR=m @@ -10631,6 +10705,7 @@ CONFIG_VCNL4035=m CONFIG_VEML3235=m CONFIG_VEML6030=m CONFIG_VEML6040=m +CONFIG_VEML6046X00=m CONFIG_VEML6070=m CONFIG_VEML6075=m CONFIG_VL6180=m @@ -10653,6 +10728,7 @@ CONFIG_MMC35240=m CONFIG_IIO_ST_MAGN_3AXIS=m CONFIG_IIO_ST_MAGN_I2C_3AXIS=m CONFIG_IIO_ST_MAGN_SPI_3AXIS=m +CONFIG_INFINEON_TLV493D=m CONFIG_SENSORS_HMC5843=m CONFIG_SENSORS_HMC5843_I2C=m CONFIG_SENSORS_HMC5843_SPI=m @@ -10828,6 +10904,7 @@ CONFIG_NTB_SWITCHTEC=m CONFIG_NTB_TRANSPORT=m CONFIG_PWM=y # CONFIG_PWM_DEBUG is not set +CONFIG_PWM_PROVIDE_GPIO=y CONFIG_PWM_CLK=m CONFIG_PWM_CRC=y CONFIG_PWM_CROS_EC=m @@ -10839,6 +10916,7 @@ CONFIG_PWM_LP3943=m CONFIG_PWM_LPSS=m CONFIG_PWM_LPSS_PCI=m CONFIG_PWM_LPSS_PLATFORM=m +CONFIG_PWM_MAX7360=m CONFIG_PWM_PCA9685=m CONFIG_PWM_TWL=m CONFIG_PWM_TWL_LED=m @@ -10911,8 +10989,8 @@ CONFIG_USB4=m # # Android # -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDERFS=y +# CONFIG_ANDROID_BINDER_IPC is not set +CONFIG_ANDROID_BINDER_IPC_RUST=y CONFIG_ANDROID_BINDER_DEVICES="" # end of Android @@ -10984,6 +11062,8 @@ CONFIG_FPGA_MGR_MICROCHIP_SPI=m CONFIG_FPGA_MGR_LATTICE_SYSCONFIG=m CONFIG_FPGA_MGR_LATTICE_SYSCONFIG_SPI=m CONFIG_TEE=m +CONFIG_TEE_DMABUF_HEAPS=y +CONFIG_OPTEE_STATIC_PROTMEM_POOL=y CONFIG_AMDTEE=m CONFIG_MULTIPLEXER=m @@ -10999,7 +11079,6 @@ CONFIG_PM_OPP=y CONFIG_SIOX=m CONFIG_SIOX_BUS_GPIO=m CONFIG_SLIMBUS=m -CONFIG_SLIM_QCOM_CTRL=m CONFIG_INTERCONNECT=y CONFIG_COUNTER=m CONFIG_INTEL_QEP=m @@ -11022,7 +11101,6 @@ CONFIG_FS_STACK=y CONFIG_BUFFER_HEAD=y CONFIG_LEGACY_DIRECT_IO=y # CONFIG_EXT2_FS is not set -# CONFIG_EXT3_FS is not set CONFIG_EXT4_FS=y CONFIG_EXT4_USE_FOR_EXT2=y CONFIG_EXT4_FS_POSIX_ACL=y @@ -11065,7 +11143,6 @@ CONFIG_BTRFS_FS_POSIX_ACL=y # CONFIG_BTRFS_DEBUG is not set # CONFIG_BTRFS_ASSERT is not set # CONFIG_BTRFS_EXPERIMENTAL is not set -# CONFIG_BTRFS_FS_REF_VERIFY is not set CONFIG_NILFS2_FS=m CONFIG_F2FS_FS=m CONFIG_F2FS_STAT_FS=y @@ -11082,18 +11159,6 @@ CONFIG_F2FS_FS_LZ4HC=y CONFIG_F2FS_FS_ZSTD=y CONFIG_F2FS_IOSTAT=y CONFIG_F2FS_UNFAIR_RWSEM=y -CONFIG_BCACHEFS_FS=m -CONFIG_BCACHEFS_QUOTA=y -# CONFIG_BCACHEFS_ERASURE_CODING is not set -CONFIG_BCACHEFS_POSIX_ACL=y -# CONFIG_BCACHEFS_DEBUG is not set -# CONFIG_BCACHEFS_TESTS is not set -CONFIG_BCACHEFS_LOCK_TIME_STATS=y -# CONFIG_BCACHEFS_NO_LATENCY_ACCT is not set -CONFIG_BCACHEFS_SIX_OPTIMISTIC_SPIN=y -# CONFIG_BCACHEFS_PATH_TRACEPOINTS is not set -# CONFIG_BCACHEFS_TRANS_KMALLOC_TRACE is not set -# CONFIG_BCACHEFS_ASYNC_OBJECT_LISTS is not set CONFIG_ZONEFS_FS=m CONFIG_FS_DAX=y CONFIG_FS_DAX_PMD=y @@ -11350,6 +11415,7 @@ CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1=y CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA=y CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2=y CONFIG_SUNRPC_DEBUG=y +# CONFIG_SUNRPC_DEBUG_TRACE is not set CONFIG_SUNRPC_XPRT_RDMA=m CONFIG_CEPH_FS=m CONFIG_CEPH_FSCACHE=y @@ -11569,6 +11635,7 @@ CONFIG_HARDENED_USERCOPY_DEFAULT_ON=y # Hardening of kernel data structures # CONFIG_LIST_HARDENED=y +# CONFIG_RUST_BITMAP_HARDENED is not set # CONFIG_BUG_ON_DATA_CORRUPTION is not set # end of Hardening of kernel data structures @@ -11605,7 +11672,7 @@ CONFIG_CRYPTO_AKCIPHER=y CONFIG_CRYPTO_KPP2=y CONFIG_CRYPTO_KPP=y CONFIG_CRYPTO_ACOMP2=y -CONFIG_CRYPTO_HKDF=y +CONFIG_CRYPTO_HKDF=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_MANAGER2=y CONFIG_CRYPTO_USER=m @@ -11628,7 +11695,6 @@ CONFIG_CRYPTO_ECC=y CONFIG_CRYPTO_ECDH=y CONFIG_CRYPTO_ECDSA=y CONFIG_CRYPTO_ECRDSA=m -CONFIG_CRYPTO_CURVE25519=m # end of Public-key cryptography # @@ -11754,7 +11820,6 @@ CONFIG_CRYPTO_USER_API_AEAD=m # # Accelerated Cryptographic Algorithms for CPU (x86) # -CONFIG_CRYPTO_CURVE25519_X86=m CONFIG_CRYPTO_AES_NI_INTEL=m CONFIG_CRYPTO_BLOWFISH_X86_64=m CONFIG_CRYPTO_CAMELLIA_X86_64=m @@ -11887,20 +11952,18 @@ CONFIG_CRYPTO_LIB_AESCFB=y CONFIG_CRYPTO_LIB_AESGCM=y CONFIG_CRYPTO_LIB_ARC4=m CONFIG_CRYPTO_LIB_GF128MUL=y -CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y -CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y -CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=y -CONFIG_CRYPTO_LIB_CHACHA_GENERIC=y +CONFIG_CRYPTO_LIB_BLAKE2S_ARCH=y CONFIG_CRYPTO_LIB_CHACHA=y -CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519=y -CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=m -CONFIG_CRYPTO_LIB_CURVE25519_INTERNAL=m +CONFIG_CRYPTO_LIB_CHACHA_ARCH=y CONFIG_CRYPTO_LIB_CURVE25519=m +CONFIG_CRYPTO_LIB_CURVE25519_ARCH=y +CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=y CONFIG_CRYPTO_LIB_DES=m -CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 -CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=y -CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m +CONFIG_CRYPTO_LIB_MD5=y CONFIG_CRYPTO_LIB_POLY1305=y +CONFIG_CRYPTO_LIB_POLY1305_ARCH=y +CONFIG_CRYPTO_LIB_POLY1305_GENERIC=y +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 CONFIG_CRYPTO_LIB_CHACHA20POLY1305=y CONFIG_CRYPTO_LIB_SHA1=y CONFIG_CRYPTO_LIB_SHA1_ARCH=y @@ -11909,9 +11972,6 @@ CONFIG_CRYPTO_LIB_SHA256_ARCH=y CONFIG_CRYPTO_LIB_SHA512=y CONFIG_CRYPTO_LIB_SHA512_ARCH=y CONFIG_CRYPTO_LIB_SM3=m -CONFIG_CRYPTO_BLAKE2S_X86=y -CONFIG_CRYPTO_CHACHA20_X86_64=y -CONFIG_CRYPTO_POLY1305_X86_64=y # end of Crypto library routines CONFIG_XXHASH=y @@ -12008,10 +12068,8 @@ CONFIG_OID_REGISTRY=y CONFIG_UCS2_STRING=y CONFIG_HAVE_GENERIC_VDSO=y CONFIG_GENERIC_GETTIMEOFDAY=y -CONFIG_GENERIC_VDSO_TIME_NS=y CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT=y CONFIG_VDSO_GETRANDOM=y -CONFIG_GENERIC_VDSO_DATA_STORE=y CONFIG_FONT_SUPPORT=y CONFIG_FONTS=y CONFIG_FONT_8x8=y @@ -12186,7 +12244,6 @@ CONFIG_DEBUG_SHIRQ=y # Debug Oops, Lockups and Hangs # # CONFIG_PANIC_ON_OOPS is not set -CONFIG_PANIC_ON_OOPS_VALUE=0 CONFIG_PANIC_TIMEOUT=0 CONFIG_LOCKUP_DETECTOR=y CONFIG_SOFTLOCKUP_DETECTOR=y @@ -12433,6 +12490,7 @@ CONFIG_ASYNC_RAID6_TEST=m # CONFIG_TEST_VMALLOC is not set # CONFIG_TEST_BPF is not set # CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_FIND_BIT_BENCHMARK_RUST is not set # CONFIG_TEST_FIRMWARE is not set # CONFIG_TEST_SYSCTL is not set # CONFIG_TEST_UDELAY is not set diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index 572581b67e..cb40098f0f 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.17.config \ No newline at end of file +../../../configs/surface-6.18.config \ No newline at end of file From 9ee3ac959c9d8ef1b92d76deae4774a1aa2cdf0f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 14:40:45 +0100 Subject: [PATCH 156/236] Update Debian kernel to v6.18.2 --- pkg/debian/kernel/version.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 10d8102cfa..a11bd3a978 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.17.13" -KERNEL_REVISION="2" +KERNEL_VERSION="6.18.2" +KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 0c56ab75c06ab7bae1a8db5049c427d31cbd35fe Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 31 Dec 2025 14:54:59 +0100 Subject: [PATCH 157/236] pkg/debian: Update patches to v6.18.2 --- ...dd-secureboot-pre-signing-to-the-kernel.patch | 10 +++++----- ...ert-integrity-Only-use-machine-keyring-.patch | 4 ++-- ...-disallow-unprivileged-CLONE_NEWUSER-by.patch | 16 ++++++++-------- ...-kbuild-Copy-config-to-target-directory.patch | 6 +++--- .../0001-kbuild-Link-sign-file-statically.patch | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch index 92065d0d6c..d836848f71 100644 --- a/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch +++ b/pkg/debian/kernel/0001-Add-secureboot-pre-signing-to-the-kernel.patch @@ -1,4 +1,4 @@ -From 011c8c949f039a5b634fd2070b4dd8d8600716ea Mon Sep 17 00:00:00 2001 +From 652e5a5d5d7263f8eaabbfdd9f8e064d897d50a3 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 22 Sep 2019 22:44:16 +0200 Subject: [PATCH] Add secureboot pre-signing to the kernel @@ -21,7 +21,7 @@ Signed-off-by: Dorian Stoll create mode 100755 scripts/sign_kernel.sh diff --git a/.gitignore b/.gitignore -index 929054df5212..5a7019ba11d0 100644 +index 86a1ba0d9035..9af120b9591b 100644 --- a/.gitignore +++ b/.gitignore @@ -161,6 +161,9 @@ signing_key.priv @@ -35,10 +35,10 @@ index 929054df5212..5a7019ba11d0 100644 /all.config /alldef.config diff --git a/arch/x86/Makefile b/arch/x86/Makefile -index 1913d342969b..131d1110044c 100644 +index 1a27efcf3c20..b62a8d5f6702 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile -@@ -320,6 +320,7 @@ endif +@@ -308,6 +308,7 @@ endif $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE) $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@ @@ -83,5 +83,5 @@ index 000000000000..d2526a279254 +sbsign --key $BUILDDIR/keys/MOK.key --cert $BUILDDIR/keys/MOK.crt \ + --output $VMLINUX $VMLINUX -- -2.51.0 +2.52.0 diff --git a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch index 961aa8e326..dd171ac092 100644 --- a/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch +++ b/pkg/debian/kernel/0001-Partially-revert-integrity-Only-use-machine-keyring-.patch @@ -1,4 +1,4 @@ -From c422df6afed4ed5337cc96588f52c628840a4ed6 Mon Sep 17 00:00:00 2001 +From b829c89ebc5a4b80f5063317655dc220310dce5a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 22:54:05 +0100 Subject: [PATCH] Partially revert "integrity: Only use machine keyring when @@ -37,5 +37,5 @@ index a401640a63cd..a1ad244cbf86 100644 static bool __init trust_moklist(void) -- -2.51.0 +2.52.0 diff --git a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch index 91dcf165bd..27a9ecdb7f 100644 --- a/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch +++ b/pkg/debian/kernel/0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch @@ -1,4 +1,4 @@ -From ba645e31140ff6ecd6a8b28f8d72cb5132f60625 Mon Sep 17 00:00:00 2001 +From a01ff076551b58aa0f69b2132018edb4ee432ab2 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Fri, 31 May 2013 19:12:12 +0100 Subject: [PATCH] add sysctl to disallow unprivileged CLONE_NEWUSER by default @@ -20,7 +20,7 @@ Signed-off-by: Serge Hallyn 3 files changed, 32 insertions(+) diff --git a/kernel/fork.c b/kernel/fork.c -index 6ca8689a83b5..483c28b98e5a 100644 +index 3da0f08615a9..8974312080fe 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -123,6 +123,12 @@ @@ -36,7 +36,7 @@ index 6ca8689a83b5..483c28b98e5a 100644 /* * Minimum number of threads to boot the kernel */ -@@ -1938,6 +1944,10 @@ __latent_entropy struct task_struct *copy_process( +@@ -1946,6 +1952,10 @@ __latent_entropy struct task_struct *copy_process( if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -47,7 +47,7 @@ index 6ca8689a83b5..483c28b98e5a 100644 /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. -@@ -3105,6 +3115,12 @@ int ksys_unshare(unsigned long unshare_flags) +@@ -3107,6 +3117,12 @@ int ksys_unshare(unsigned long unshare_flags) if (unshare_flags & CLONE_NEWNS) unshare_flags |= CLONE_FS; @@ -92,12 +92,12 @@ index cb6196e3fa99..c955e49a4b7a 100644 { .procname = "sysctl_writes_strict", diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c -index 682f40d5632d..bf265ad528f9 100644 +index 03cb63883d04..163817801c17 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c -@@ -22,6 +22,9 @@ - #include +@@ -23,6 +23,9 @@ #include + #include +/* sysctl */ +int unprivileged_userns_clone = 1; @@ -106,5 +106,5 @@ index 682f40d5632d..bf265ad528f9 100644 static DEFINE_MUTEX(userns_state_mutex); -- -2.51.0 +2.52.0 diff --git a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch index 38b940582f..d605f73072 100644 --- a/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch +++ b/pkg/debian/kernel/0001-kbuild-Copy-config-to-target-directory.patch @@ -1,4 +1,4 @@ -From 62bc6c700904071cd13e3baa8117e94f7e6a571d Mon Sep 17 00:00:00 2001 +From fa4618b49419f0c64e2f2e83c2f2c1a42ae6fb79 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 03:02:20 +0200 Subject: [PATCH] kbuild: Copy config to target directory @@ -8,7 +8,7 @@ Subject: [PATCH] kbuild: Copy config to target directory 1 file changed, 3 insertions(+) diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build -index b96538787f3d..718bd64d060e 100755 +index 2576cf7902db..7b30ee536a43 100755 --- a/scripts/package/install-extmod-build +++ b/scripts/package/install-extmod-build @@ -68,4 +68,7 @@ if [ "${CC}" != "${HOSTCC}" ]; then @@ -20,5 +20,5 @@ index b96538787f3d..718bd64d060e 100755 + find "${destdir}" \( -name '.*.cmd' -o -name '*.o' \) -delete -- -2.51.0 +2.52.0 diff --git a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch index 4f8ab6a299..e2fec6571e 100644 --- a/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch +++ b/pkg/debian/kernel/0001-kbuild-Link-sign-file-statically.patch @@ -1,4 +1,4 @@ -From c6be12fd8b6b036ca919511cd947c5d18cf03844 Mon Sep 17 00:00:00 2001 +From 1eaf0059243d5f02ef579758629b7f7b1e2777b5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 30 Jun 2024 17:10:28 +0200 Subject: [PATCH] kbuild: Link sign-file statically @@ -21,5 +21,5 @@ index 46f860529df5..7846e18ef5d8 100644 ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) -- -2.51.0 +2.52.0 From 25474d5cfd46c5cd02c325618d5a97cdf71b0005 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Sun, 4 Jan 2026 00:06:39 -0800 Subject: [PATCH 158/236] Update build for v6.18.3-arch1 and update checksums --- pkg/arch/kernel/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 69d754643c..545e2237ca 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.18.2.arch2 +pkgver=6.18.3.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -64,7 +64,7 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('63794d6bd1c8f2ca7a023ce333e3a26c423637dd0fdefe612e2950e6604190b6' +sha256sums=('b5af77758935f761ee42b9aa407809bb1dc5fd15ee379a73f66e14c7dca75300' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' From bed0762f751b32d4952eeee6b5cd9a6fb7928f94 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 4 Jan 2026 20:46:37 +0100 Subject: [PATCH 159/236] Update Debian kernel to v6.18.3 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index a11bd3a978..d935d9daff 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.18.2" +KERNEL_VERSION="6.18.3" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 7ff104358bb3e84b4f8ce705f2a58d1c07750737 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Sun, 4 Jan 2026 19:20:59 -0800 Subject: [PATCH 160/236] Update patches to fix shutdown on Surface Laptop Studio 2 --- patches/6.18/0011-surface-shutdown.patch | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index 8895404c2e..ace67f22a1 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -95,3 +95,43 @@ index bf97d49c23cf..90eead93d825 100644 -- 2.52.0 +From e476fff3b08b640d546937028cf1edd37408bd40 Mon Sep 17 00:00:00 2001 +From: LegendaryFire +Date: Sun, 4 Jan 2026 19:14:33 -0800 +Subject: [PATCH] Fix powering down on Surface Laptop Studio 2 + +--- + drivers/pci/quirks.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index ce4c0da99537..955da6ea31bf 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6360,6 +6360,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop Studio 2", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop Studio 2"), ++ }, ++ }, + {} + }; + +@@ -6377,3 +6384,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thu + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa76e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa71e, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa73f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa73e, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa7a0, quirk_no_shutdown); // GPU +\ No newline at end of file +-- +2.52.0 + From f4ae0e3409ff2f2f8907971486fc2a06d54eb6e0 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Sun, 4 Jan 2026 19:21:57 -0800 Subject: [PATCH 161/236] Update arch build package sums --- pkg/arch/kernel/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 545e2237ca..ae1adad3ee 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -78,7 +78,7 @@ sha256sums=('b5af77758935f761ee42b9aa407809bb1dc5fd15ee379a73f66e14c7dca75300' '421ef29f1fd0f100d3d47b7329c6ea6d77a7164d0b6834e18512f20df499120b' 'fd1d4c7604f58b877c2a92ea3c8fca55d13bb030dea19fb18675d053254acadb' 'abc3c0bcc3b2f4482277053584f9262800d47644a9fd5aa9e25585346479becf' - '0ee51e05ad327bfd57c9ea574badc48a07ed364b81cb30718abacdb04a912f86' + '8b020665acc4c03af049ec3a856c7062cab69804ca2db79da7ba736752a9aa7e' 'a902ec0578d242bbfc9f52b644d10c5c9b9a2a7041177a1c94c2e51d1eb7d4a1' '6dfe7895614a445ae03bc02db8081d3030c9cd81f0b678c240d699c539d293ff' 'd255744eddcf2a4e1fc8f88e611aa97befea10aa572402866a870815d0a75b06' From 7638d313cef23e2c8533aefba14d4fd59418c91d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 7 Jan 2026 01:15:34 +0100 Subject: [PATCH 162/236] patches/v6.18: Rebase --- patches/6.18/0001-secureboot.patch | 4 ++-- patches/6.18/0002-surface3.patch | 4 ++-- patches/6.18/0003-mwifiex.patch | 10 +++++----- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 6 +++--- patches/6.18/0006-ithc.patch | 6 +++--- patches/6.18/0007-surface-sam.patch | 4 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 4 ++-- patches/6.18/0009-surface-button.patch | 4 ++-- patches/6.18/0010-surface-typecover.patch | 6 +++--- patches/6.18/0011-surface-shutdown.patch | 21 +++++++++++--------- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 20 +++++++++---------- patches/6.18/0014-amd-gpio.patch | 4 ++-- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 4 ++-- 16 files changed, 53 insertions(+), 50 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index c386ade7ba..6b7059c6e3 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From d6fc570bbe52fc8a59710505fae4330930dc9583 Mon Sep 17 00:00:00 2001 +From 25a3cacb23bd76c57052e9d33ddc39b457ae2c28 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 -- 2.52.0 -From 4c96a0c3cedd2513ef41b7bcb393ee2713b28433 Mon Sep 17 00:00:00 2001 +From de4f7cfd4e2b7a538eb11a7adc8619af3af51d5c Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index 2d259c03f1..b34a30c742 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 3cf19f7024c337cb241bdac922aa4f7c49230d2d Mon Sep 17 00:00:00 2001 +From cd774dcb0460ea32fa5fb5f68bf1842ff16785a9 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.52.0 -From e7be2c605bdf261b99181c9c316c11b7bb3429c2 Mon Sep 17 00:00:00 2001 +From 81f6b6fe5b65630bf1ede3bd312011feb7c5a5f6 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 1b983842a6..569a9ae739 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 789e7b03d5dcb9855effc613417cc90809934f83 Mon Sep 17 00:00:00 2001 +From 2fd01f55dca7bcb79337d8d5b634220eefe8d94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.52.0 -From fbdeed3f7949e8ceda8aa6d2c1be6c642cd8a07e Mon Sep 17 00:00:00 2001 +From c365824e93d36158f175f6a4d0d44187b1581c19 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.52.0 -From 79e33cc32e6967326cc481ed46455256bbff0412 Mon Sep 17 00:00:00 2001 +From a880e786693cfd209e5995d8ad37741d2be37d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index fa683bb7f0b4..f80e194aa970 100644 +index b92bfd131567..4899dc2bb490 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index fa683bb7f0b4..f80e194aa970 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4177,6 +4179,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4188,6 +4190,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index c9684d0470..822827362f 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 718f88769376a3d9ef0f82f30be3966b87e852f3 Mon Sep 17 00:00:00 2001 +From de159f5dda4408ed6227313e95aa80457b9a888a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 140c73e722..e2253bcaf8 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 19f6c954871b35178a9a87aec7ec52f538a9bfb6 Mon Sep 17 00:00:00 2001 +From 39c4ce6999998717128ece65117ebaa151ff6032 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 73cad914be9f..807e352af059 100644 -- 2.52.0 -From 52d2afc33b2e824f47c7a4f32dc637ca8fc72f45 Mon Sep 17 00:00:00 2001 +From 8df324adc035358f6a5d4dbb0dc0816c4d706d44 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e236c7ec221f..9e31a5fe1f66 100644 -- 2.52.0 -From 20e764ff7f650b1b6472e06d0b8e43bf72cb98e7 Mon Sep 17 00:00:00 2001 +From 4fbea7826d9bb3ee99d3483bc1dd35cca93abf13 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index 50f3fb5208..c6093f21e5 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From c7f172907387d835fb993fbbfa9260375026bd97 Mon Sep 17 00:00:00 2001 +From 128847caa31eebe781584112d55f7a97fbbaff5c Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,7 +10,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 4f9b01dc91e8..e4d73e45473c 100644 +index 8bcbfe3d9c72..c78806d35f2b 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) @@ -39,7 +39,7 @@ index 4f9b01dc91e8..e4d73e45473c 100644 -- 2.52.0 -From a8912e19c8afad3e6c24d9ea5184c590f1eeaa51 Mon Sep 17 00:00:00 2001 +From 28652a8c89b32522a705b93661a5bf00412a012a Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index ec207921ba..4e669edfd4 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 3850f3e3beff859fab3d3d0b1f6e0be3fc4d46dc Mon Sep 17 00:00:00 2001 +From e8e5de942e8dae7826866ab63d687071bf4e08fd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.52.0 -From 1935dca81444254be728b48fefc3ce42f2d3c3da Mon Sep 17 00:00:00 2001 +From 49dfbe3512bb85eb4fe49a6998151fac777ee74c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 75cdd15e94..6a10a2c9b6 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From b0afc4791a622f2f35a94f4be73f560d08967128 Mon Sep 17 00:00:00 2001 +From 342de48e39eb9303d8044da0c4a5dbe509583cfc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a27b7..070c36637811 100644 -- 2.52.0 -From ec63ad179736cec451a38c2a55cbc1ebb8d31356 Mon Sep 17 00:00:00 2001 +From 73a2034c5dfb1e594d2b8532cfa8deedf4c09dc0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index d050f23647..4319f53b25 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 77d4b30b68796c78613ba69c4a53745531d774f9 Mon Sep 17 00:00:00 2001 +From 8fc811e764ac2db7d7f3e4ec5620778d00af5490 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.52.0 -From 7c2976cf057b485aca52b60a0969de085f75b0f0 Mon Sep 17 00:00:00 2001 +From b356c8c66cbdcf6cbf0872cb45a09bb80f95ba77 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index bd3d0c953f..469ae06840 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From cf96145d5c827b8fcc831e6ff05f76a27ab4713b Mon Sep 17 00:00:00 2001 +From a317e20b19b8f0abd0afc2fb1abc4359346bd9bf Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 47f589c4104a..6b00aec67ee2 100644 -- 2.52.0 -From 27182ab01f104e701b0f2fe835a4d257176c156c Mon Sep 17 00:00:00 2001 +From e6305ccb279e30c5fe2848e4fb5cedef2d2c81d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 179dc316b4b5..7d644e1c445e 100644 -- 2.52.0 -From 5bc896710a3e3db40f4b7351585eb811f3673087 Mon Sep 17 00:00:00 2001 +From 95603cd2fe1581f1131e4e5300f0a02a2bf146c1 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index ace67f22a1..f0da8b635c 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 4864694f8b95bf1bdffc5fd607334c408d9b73c6 Mon Sep 17 00:00:00 2001 +From 790ea29fa1c48f6ff4cf5bda8ce549c8ee5a740a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,17 +95,20 @@ index bf97d49c23cf..90eead93d825 100644 -- 2.52.0 -From e476fff3b08b640d546937028cf1edd37408bd40 Mon Sep 17 00:00:00 2001 +From a4f65698937823a5e3210932c52640ac2115837e Mon Sep 17 00:00:00 2001 From: LegendaryFire -Date: Sun, 4 Jan 2026 19:14:33 -0800 -Subject: [PATCH] Fix powering down on Surface Laptop Studio 2 +Date: Wed, 7 Jan 2026 01:06:25 +0100 +Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops + quirk +Link: https://github.com/linux-surface/linux-surface/pull/1948 +Patchset: surface-shutdown --- - drivers/pci/quirks.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) + drivers/pci/quirks.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index ce4c0da99537..955da6ea31bf 100644 +index ce4c0da99537..fdc410bf70e5 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6360,6 +6360,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { @@ -122,16 +125,16 @@ index ce4c0da99537..955da6ea31bf 100644 {} }; -@@ -6377,3 +6384,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thu +@@ -6377,3 +6384,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thu DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU ++ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa76e, quirk_no_shutdown); // Thunderbolt 4 USB Controller +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa71e, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa73f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa73e, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa7a0, quirk_no_shutdown); // GPU -\ No newline at end of file -- 2.52.0 diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index d7645e2ff2..4d2f11676a 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 4145812a4cb6093d473918ce72f693dd47c9c586 Mon Sep 17 00:00:00 2001 +From 21cc80c64c4e7e19cf84311dcc6ecaee4992e03b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index b58adc827a..b9c5ba715f 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From fb2e71467ce8c2b49ba8b1993ed6cf6695d35371 Mon Sep 17 00:00:00 2001 +From cefa9f598d93854ddcfa9cbe9ac4037302aaa3bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2949..a6bad2679a0c 100644 -- 2.52.0 -From 4d2eeed56d6d694a2068edbf1cf9c80ff53c143e Mon Sep 17 00:00:00 2001 +From 8342d01a60e39e5b4d63676a1cb18bab6207974a Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 9e31a5fe1f66..bdd32551c452 100644 -- 2.52.0 -From 7eca7549a279d6424558df5b9b18447830763f9e Mon Sep 17 00:00:00 2001 +From 31367eafab6cb5efba28fcf10b0aadc232f20041 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.52.0 -From a45541d86bd42201c0f6c34c164ff6bf5ff43454 Mon Sep 17 00:00:00 2001 +From 274297ffcb3d62e37c70cd0253ad1337f7e4309b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0175..28b192c9a5ec 100644 -- 2.52.0 -From 3eebeb1855e4459c7a55828ca2cbbe29952531d4 Mon Sep 17 00:00:00 2001 +From 3dd814b0a0cea2567fdd4cd8eb4588e9c2d7cac6 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.52.0 -From f6625936b705d9198988eb6d5beb9e0c3531e5cf Mon Sep 17 00:00:00 2001 +From 6f85ab5fb6634424be51cd48c64afe2c2ea33796 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.52.0 -From 83ea382cbc7c27b5b2876ed187a79aae8e4f44d7 Mon Sep 17 00:00:00 2001 +From bae4749173191a62d8642bacf509eccde0885496 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.52.0 -From fbb539345d7b7399b642c8ac3960a4001ade98fa Mon Sep 17 00:00:00 2001 +From 723a45f016aaea13b412ce65a97ae4f3a9923117 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.52.0 -From 6cd252af01846bf35a2968baccc8d427ff6fa660 Mon Sep 17 00:00:00 2001 +From b3d71cf5004c1b6ff0a388bd1bc098fdb61baca8 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb981f2..e03a1d8cdcb4 100644 -- 2.52.0 -From 749e03034a13b36f5ccf23e9f9fc71057ea430bc Mon Sep 17 00:00:00 2001 +From c09eeb95e641f3b06201490b265a453c9ff3ddce Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 72d596ec9e..61df12b683 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From e06ddb701b0458b770996b893ae0acf996f51d51 Mon Sep 17 00:00:00 2001 +From 8caf1b179f3d3db1c3d4bc43138a2b604eb9a1a3 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95eb3..8914a922be2b 100644 -- 2.52.0 -From 4532af4e877be51a6f501f99e76c6632214516e3 Mon Sep 17 00:00:00 2001 +From df07e32f7e0fe91d48c2f8273f356c1de98cdbb0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 740a0d0425..978fc526ed 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From d5457f13b006eebde52dc706320ea546cdc0c9a0 Mon Sep 17 00:00:00 2001 +From aba054883847d06315ebc5a040f9fdfbe643de03 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index 56afd4a1fa..aeece6a6d8 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 647ba0853323d287d240377d5ecfa79c9872e96f Mon Sep 17 00:00:00 2001 +From 4e8ff7f09c09feca6bae9d364c0bd43e479cb03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000000..a171ea65672f -- 2.52.0 -From 1cc181c914274d50fcb69c7c8d7db9a691811f2c Mon Sep 17 00:00:00 2001 +From 77881180b23cb98a470a4864fa0af3785a5ed14a Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 From 72ffe897ff88378c13494e8eb10620151279cc24 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 7 Jan 2026 01:20:29 +0100 Subject: [PATCH 163/236] pkg/arch: Bump release version --- pkg/arch/kernel/PKGBUILD | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index ae1adad3ee..9ac7be6209 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -4,7 +4,7 @@ pkgbase=linux-surface pkgver=6.18.3.arch1 -pkgrel=1 +pkgrel=2 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -68,22 +68,22 @@ sha256sums=('b5af77758935f761ee42b9aa407809bb1dc5fd15ee379a73f66e14c7dca75300' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '0e60408275c4dfd30f61fc6a6fabfa9d26e6589a05caf845d8b5eee10744cbe0' - 'd151ce001d297e067b11622f344995567333aad39fc444e0bdcd15814cdac75c' - 'ed4aae3076432cb2ed28ac0058d4fd9eea402b3ed3e75fb1863527c653089727' - 'c2e5c1f6234aa7c993a79feefc31f4a0395c2175cf2072d0abc047b4830e13aa' - 'c17f7b0a2b54f88ed66f4cf35fd59ad81749e3f51b89ed6324c3672707928e3a' - '2d75bc845525de78f73a1125258e500a46ad1129e8bd67bc5af432f4874dcd28' - 'c9eaa118300655b822f01e6379902b2ad65fa246074c1669e80c48bf1586a1a9' - '421ef29f1fd0f100d3d47b7329c6ea6d77a7164d0b6834e18512f20df499120b' - 'fd1d4c7604f58b877c2a92ea3c8fca55d13bb030dea19fb18675d053254acadb' - 'abc3c0bcc3b2f4482277053584f9262800d47644a9fd5aa9e25585346479becf' - '8b020665acc4c03af049ec3a856c7062cab69804ca2db79da7ba736752a9aa7e' - 'a902ec0578d242bbfc9f52b644d10c5c9b9a2a7041177a1c94c2e51d1eb7d4a1' - '6dfe7895614a445ae03bc02db8081d3030c9cd81f0b678c240d699c539d293ff' - 'd255744eddcf2a4e1fc8f88e611aa97befea10aa572402866a870815d0a75b06' - 'ca47c4c1a997686f70d410846e221de857e698e02058889d04c8338bfd7850a5' - '8544821a0ad3c2757aa99662a785df6df17d6a21fd084c03cf4b73b0c4602341') + 'ace28c38ca03c0fdc66b265e3ef2b7a0153740c0eb815ff6cdfc5d2df3f12580' + '38bf267d08ea74dc0a0762c92eb6512e7c2a786af4eab1a3856dd03ce6a35246' + '5b994cc6deeb2205f97b600721363d006ccfaf9453b3d15c4bec4c10b53c7ff6' + 'ef472c1e49e46744ab588d591b25cfe6b2d465e67aba227da9db91931fec969a' + '6a6e359e461bc888752fa60251331a97b6a1a99944d316d65cb2ac7148415794' + 'b843d8f38827a34e73ee602469a0eb9d43e29d3e5061aa11b3bc22ff384d2c8c' + '282a9de0adfd5298274c62e865983932e18cd759318dcad60108ad2928029d9e' + 'c80b11ea2c15ed69abb4befad0c8cba096a3f0a46f70f40a6242c812aaa25b31' + 'f7f0f9306350409efdcd5a126f70286aa1a4b261bae869273b40584cc2568c65' + '17f01763f4b44703d2a788f2756bac91ce7d872db66372223ef77302f032927b' + '0b7030f27ca965acc944c1f924f1a89e91b25a344bdbc9f6a6945bc8ee4ad197' + 'f613337f549cdcbf57444f0ab67cfb2d12eb84a003bcec1be887f6508eac9953' + '86a89eb63f8783d395a44fa304cde866802ec8072d1ea2e2eafd0f7f1e9e7dbb' + 'e064ea18c367a55e439081551792a9609a50f4fcc7732bb287f13cb62bb07b69' + 'f1ba0a216c6622d79e8618c37a4f298d06053edb9b829f235472feeee7bbcf24' + '2dbcd9e2115346415cedc0e85fa729d1ac5ef2e47ab8d5d04c6c5dfb482287fc') export KBUILD_BUILD_HOST=archlinux From b86b28b7ae14ea836269525a7fe18a10b946947b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 7 Jan 2026 01:22:06 +0100 Subject: [PATCH 164/236] pkg/debian: Bump release version --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index d935d9daff..390a134c93 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ KERNEL_VERSION="6.18.3" -KERNEL_REVISION="1" +KERNEL_REVISION="2" KERNEL_LOCALVERSION="-surface" From 9148d5c6b05cb50f291e1f2bb5c68c2ed687980b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 7 Jan 2026 01:24:29 +0100 Subject: [PATCH 165/236] pkg/fedora: Bump release --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 49af946600..42f7deb487 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -25,7 +25,7 @@ ## The release number of the modified kernel package. ## e.g. 300 for kernel-6.3.1-300.fc38.foo ## -PACKAGE_RELEASE = "3" +PACKAGE_RELEASE = "4" ## ## Build options for configuring which parts of the kernel package are enabled. From 4e8d45acb3c5c5aff7742c83d8ebbd4b3248a002 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 8 Jan 2026 22:03:30 +0100 Subject: [PATCH 166/236] .github: Add workflow for auto-generating patches from kernel repo Allows specifying a kernel branch and then automatically generates the updated patches from that, creating a PR on successful completion. --- .../scripts/autoupdate/generate-patches.sh | 252 ++++++++++++++++++ .github/workflows/generate-patches.yml | 151 +++++++++++ 2 files changed, 403 insertions(+) create mode 100755 .github/scripts/autoupdate/generate-patches.sh create mode 100644 .github/workflows/generate-patches.yml diff --git a/.github/scripts/autoupdate/generate-patches.sh b/.github/scripts/autoupdate/generate-patches.sh new file mode 100755 index 0000000000..25102aa52b --- /dev/null +++ b/.github/scripts/autoupdate/generate-patches.sh @@ -0,0 +1,252 @@ +#!/usr/bin/env bash +# +# Generate kernel patches from linux-surface/kernel repository +# +# This script: +# 1. Clones the linux-surface/kernel repository +# 2. Detects the base kernel version using git describe +# 3. Uses git-format-patchsets to generate patches +# 4. Outputs patches to the appropriate directory +# +# Environment variables: +# KERNEL_BRANCH: The kernel branch to process (e.g., "v6.18-surface") +# BASE_VERSION_TAG: (optional) Base version tag to use (e.g., "v6.18.4") +# If not specified, auto-detected using git describe +# FORCE_UPDATE: (optional) Force update even if no changes + +set -euo pipefail + +# Enable debug mode if DEBUG is set +if [ "${DEBUG:-}" = "1" ]; then + set -x +fi + +# ============================================================================ +# Configuration and validation +# ============================================================================ + +if [ -z "${KERNEL_BRANCH:-}" ]; then + echo "ERROR: KERNEL_BRANCH environment variable is required" + echo "Example: KERNEL_BRANCH=v6.18-surface" + exit 1 +fi + +# Get absolute paths +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" +WORK_DIR="${REPO_ROOT}/.tmp-patch-gen" + +# Configuration +KERNEL_REPO="https://github.com/linux-surface/kernel" +GIT_TOOLS_REPO="https://github.com/qzed/git-tools" + +echo "============================================" +echo "Generating patches for kernel branch ${KERNEL_BRANCH}" +echo "============================================" +echo "Kernel repo: ${KERNEL_REPO}" +echo "Branch: ${KERNEL_BRANCH}" +echo "" + +# ============================================================================ +# Setup working directory +# ============================================================================ + +echo "[1/6] Setting up working directory..." +rm -rf "${WORK_DIR}" +mkdir -p "${WORK_DIR}" +cd "${WORK_DIR}" + +# ============================================================================ +# Clone kernel repository +# ============================================================================ + +echo "[2/6] Cloning kernel repository..." + +# Clone with limited history depth to get all our added patches. +# Depth 250 should be sufficient to reach the base tag in most cases. +if ! git clone --depth=250 --branch="${KERNEL_BRANCH}" "${KERNEL_REPO}" kernel; then + echo "ERROR: Failed to clone kernel repository" + echo "Check that branch '${KERNEL_BRANCH}' exists" + exit 1 +fi + +cd kernel + +echo "Successfully cloned ${KERNEL_BRANCH}" + +# ============================================================================ +# Detect base kernel version +# ============================================================================ + +echo "[3/6] Detecting base kernel version..." + +# Check if BASE_VERSION_TAG was provided as input +if [ -n "${BASE_VERSION_TAG:-}" ]; then + echo "Using provided base version tag: ${BASE_VERSION_TAG}" + + # Validate format + if ! echo "${BASE_VERSION_TAG}" | grep -qE '^v[0-9]+\.[0-9]+(\.[0-9]+)?$'; then + echo "ERROR: Invalid base version tag format: ${BASE_VERSION_TAG}" + echo "Expected format: vX.Y or vX.Y.Z (e.g., v6.18, v6.18.4)" + exit 1 + fi + + # Verify the provided tag exists + if ! git rev-parse "${BASE_VERSION_TAG}" >/dev/null 2>&1; then + echo "ERROR: Provided base version tag '${BASE_VERSION_TAG}' not found in repository" + exit 1 + fi +else + echo "Auto-detecting base version using git describe..." + + # Use git describe to find the base version tag + # Pattern: v[0-9]*.[0-9]* matches vX.Y or vX.Y.Z (e.g., v6.18, v6.18.4, v7.0, v7.0.1) + # This requires at least one digit after 'v' and after the first dot + BASE_VERSION=$(git describe --tags --match='v[0-9]*.[0-9]*' 2>/dev/null || true) + + if [ -z "${BASE_VERSION}" ]; then + echo "ERROR: Could not detect base kernel version using git describe" + echo "Make sure the kernel branch has proper version tags" + exit 1 + fi + + # Extract just the version tag using grep + # This handles formats like: v6.18, v6.18.4, v6.18.4-123-gabcdef + BASE_VERSION_TAG=$(echo "${BASE_VERSION}" | grep -oE 'v[0-9]+\.[0-9]+(\.[0-9]+)?' | head -1) + + if [ -z "${BASE_VERSION_TAG}" ]; then + echo "ERROR: Could not extract version tag from: ${BASE_VERSION}" + exit 1 + fi + + echo "Detected base version: ${BASE_VERSION}" +fi + +# Extract kernel major.minor version from base tag (e.g., v6.18.4 → 6.18, v6.18 → 6.18) +KERNEL_VERSION=$(echo "${BASE_VERSION_TAG}" | sed -E 's/^v([0-9]+\.[0-9]+)(\.[0-9]+)?$/\1/') + +if [ -z "${KERNEL_VERSION}" ]; then + echo "ERROR: Could not extract kernel version from tag: ${BASE_VERSION_TAG}" + exit 1 +fi + +echo "Base version tag: ${BASE_VERSION_TAG}" +echo "Kernel version: ${KERNEL_VERSION}" + +# Set patches directory based on detected version +PATCHES_DIR="${REPO_ROOT}/patches/${KERNEL_VERSION}" +echo "Patches directory: ${PATCHES_DIR}" +echo "" + +# ============================================================================ +# Install git-format-patchsets tool +# ============================================================================ + +echo "[4/6] Installing git-format-patchsets..." + +cd "${WORK_DIR}" +git clone --depth=1 "${GIT_TOOLS_REPO}" git-tools + +# git-format-patchsets is a bash script, make it executable and add to PATH +chmod +x git-tools/git-format-patchsets +export PATH="${WORK_DIR}/git-tools:${PATH}" + +# Verify tool is available +if ! command -v git-format-patchsets >/dev/null 2>&1; then + echo "ERROR: git-format-patchsets not found in PATH" + exit 1 +fi + +echo "Successfully installed git-format-patchsets" + +# ============================================================================ +# Generate patches +# ============================================================================ + +echo "[5/6] Generating patches..." + +cd "${WORK_DIR}/kernel" + +# Generate patches using git-format-patchsets +# Flags: +# -t: Extract patchset assignments from "Patchset:" tags +# --no-confirm: Don't ask for confirmation (non-interactive) +# Note: Patches are generated in the current directory (kernel dir) +PATCH_RANGE="${BASE_VERSION_TAG}" + +echo "Generating patches from range: ${PATCH_RANGE}" + +# Run git-format-patchsets with proper error handling +if ! git-format-patchsets -t --no-confirm "${PATCH_RANGE}"; then + echo "ERROR: git-format-patchsets failed" + exit 1 +fi + +# Count generated patches in current directory +PATCH_COUNT=$(find . -maxdepth 1 -name "*.patch" 2>/dev/null | wc -l) +echo "Generated ${PATCH_COUNT} patch files" + +if [ "${PATCH_COUNT}" -eq 0 ]; then + echo "WARNING: No patches were generated" + if [ "${FORCE_UPDATE:-false}" != "true" ]; then + echo "Skipping update (use FORCE_UPDATE=true to force)" + echo "has_changes=false" >> "${GITHUB_OUTPUT:-/dev/null}" + exit 0 + fi +fi + +# ============================================================================ +# Update patches directory +# ============================================================================ + +echo "[6/6] Updating patches directory..." + +# Create/clear the patches directory +mkdir -p "${PATCHES_DIR}" +rm -f "${PATCHES_DIR}"/*.patch + +# Copy generated patches from kernel directory +if [ "${PATCH_COUNT}" -gt 0 ]; then + mv "${WORK_DIR}/kernel"/*.patch "${PATCHES_DIR}/" + echo "Copied ${PATCH_COUNT} patches to ${PATCHES_DIR}" +fi + +# ============================================================================ +# Verify and report +# ============================================================================ + +echo "" +echo "============================================" +echo "Patch generation complete!" +echo "============================================" +echo "Branch: ${KERNEL_BRANCH}" +echo "Base version: ${BASE_VERSION_TAG}" +echo "Kernel version: ${KERNEL_VERSION}" +echo "Patches generated: ${PATCH_COUNT}" +echo "Output directory: ${PATCHES_DIR}" +echo "" + +# List generated patches +if [ "${PATCH_COUNT}" -gt 0 ]; then + echo "Generated patches:" + ls -1 "${PATCHES_DIR}"/*.patch | sort + echo "" +fi + +# Set output for GitHub Actions +if [ -n "${GITHUB_OUTPUT:-}" ]; then + echo "has_changes=true" >> "${GITHUB_OUTPUT}" + echo "patch_count=${PATCH_COUNT}" >> "${GITHUB_OUTPUT}" + echo "base_version=${BASE_VERSION_TAG}" >> "${GITHUB_OUTPUT}" + echo "kernel_version=${KERNEL_VERSION}" >> "${GITHUB_OUTPUT}" +fi + +# ============================================================================ +# Cleanup +# ============================================================================ + +echo "Cleaning up temporary files..." +cd "${REPO_ROOT}" +rm -rf "${WORK_DIR}" + +echo "Done!" diff --git a/.github/workflows/generate-patches.yml b/.github/workflows/generate-patches.yml new file mode 100644 index 0000000000..e648bf7059 --- /dev/null +++ b/.github/workflows/generate-patches.yml @@ -0,0 +1,151 @@ +name: Generate Kernel Patches + +on: + # Manual trigger with inputs + workflow_dispatch: + inputs: + branch: + description: 'Kernel branch to update (e.g., "v6.18-surface")' + required: true + type: string + base_version: + description: 'Base version tag (optional, e.g., "v6.18.4"). If not specified, auto-detected with git describe' + required: false + type: string + force: + description: 'Force update even if no changes detected' + required: false + type: boolean + default: false + +jobs: + generate: + name: Generate patches for ${{ inputs.branch }} + runs-on: ubuntu-latest + + steps: + - name: Checkout linux-surface repo + uses: actions/checkout@v4 + with: + token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + fetch-depth: 0 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y git + + - name: Generate patches + id: generate + env: + KERNEL_BRANCH: ${{ inputs.branch }} + BASE_VERSION_TAG: ${{ inputs.base_version }} + FORCE_UPDATE: ${{ inputs.force }} + run: | + bash .github/scripts/autoupdate/generate-patches.sh + + - name: Check if changes exist + id: check + run: | + if [ "${{ steps.generate.outputs.has_changes }}" = "true" ]; then + echo "has_changes=true" >> $GITHUB_OUTPUT + else + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "No changes detected, skipping PR creation" + fi + + - name: Setup git identity + if: steps.check.outputs.has_changes == 'true' + run: | + git config user.name "surfacebot" + git config user.email "surfacebot@users.noreply.github.com" + + - name: Create branch and commit changes + if: steps.check.outputs.has_changes == 'true' + id: commit + run: | + # Extract kernel version and base version from script outputs + KERNEL_VERSION="${{ steps.generate.outputs.kernel_version }}" + BASE_VERSION="${{ steps.generate.outputs.base_version }}" + PATCH_COUNT="${{ steps.generate.outputs.patch_count }}" + + # Create unique branch name with timestamp + TIMESTAMP=$(date +%Y%m%d-%H%M%S) + BRANCH="autoupdate/patches-v${KERNEL_VERSION}-${TIMESTAMP}" + echo "branch=${BRANCH}" >> $GITHUB_OUTPUT + echo "kernel_version=${KERNEL_VERSION}" >> $GITHUB_OUTPUT + echo "base_version=${BASE_VERSION}" >> $GITHUB_OUTPUT + + # Create and switch to new branch + git checkout -b "${BRANCH}" + + # Stage changes in patches directory + git add patches/${KERNEL_VERSION}/ + + # Check if there are actual changes to commit + if git diff --cached --quiet; then + echo "No changes to commit" + echo "committed=false" >> $GITHUB_OUTPUT + exit 0 + fi + + # Create commit message + cat > /tmp/commit-msg <> $GITHUB_OUTPUT + + - name: Push branch + if: steps.check.outputs.has_changes == 'true' && steps.commit.outputs.committed == 'true' + run: | + git push -u origin "${{ steps.commit.outputs.branch }}" + + - name: Create Pull Request + if: steps.check.outputs.has_changes == 'true' && steps.commit.outputs.committed == 'true' + env: + GH_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + run: | + KERNEL_VERSION="${{ steps.commit.outputs.kernel_version }}" + BASE_VERSION="${{ steps.commit.outputs.base_version }}" + PATCH_COUNT="${{ steps.generate.outputs.patch_count }}" + BRANCH="${{ inputs.branch }}" + + gh pr create \ + --title "patches/v${KERNEL_VERSION}: Automatic update to ${BASE_VERSION}" \ + --body "$(cat < Date: Fri, 9 Jan 2026 00:59:30 +0100 Subject: [PATCH 167/236] .github: Add workflow for auto-rebasing kernel branches --- .github/data/autoupdate/kernel-base.config | 1 + .../data/autoupdate/kernel-overrides.config | 26 ++ .github/scripts/autoupdate/build-kernel.sh | 198 +++++++++++++ .github/scripts/autoupdate/rebase-kernel.sh | 268 ++++++++++++++++++ .github/workflows/rebase-kernel.yml | 184 ++++++++++++ 5 files changed, 677 insertions(+) create mode 120000 .github/data/autoupdate/kernel-base.config create mode 100644 .github/data/autoupdate/kernel-overrides.config create mode 100755 .github/scripts/autoupdate/build-kernel.sh create mode 100755 .github/scripts/autoupdate/rebase-kernel.sh create mode 100644 .github/workflows/rebase-kernel.yml diff --git a/.github/data/autoupdate/kernel-base.config b/.github/data/autoupdate/kernel-base.config new file mode 120000 index 0000000000..af2da35b4b --- /dev/null +++ b/.github/data/autoupdate/kernel-base.config @@ -0,0 +1 @@ +../../../pkg/arch/kernel/config \ No newline at end of file diff --git a/.github/data/autoupdate/kernel-overrides.config b/.github/data/autoupdate/kernel-overrides.config new file mode 100644 index 0000000000..e18e444ab7 --- /dev/null +++ b/.github/data/autoupdate/kernel-overrides.config @@ -0,0 +1,26 @@ +## +## Forcefully disable debug symbols +## + +CONFIG_DEBUG_INFO_NONE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_BTF is not set +# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +# CONFIG_DEBUG_INFO_DWARF5 is not set + +## +## Prevent BPF stuff from comlaining during boot because we have debug info disabled +## + +# CONFIG_BPF_PRELOAD is not set + +## +## ASHMEM / BINDERFS +## + +CONFIG_ASHMEM=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y +CONFIG_ANDROID_BINDER_DEVICES="" diff --git a/.github/scripts/autoupdate/build-kernel.sh b/.github/scripts/autoupdate/build-kernel.sh new file mode 100755 index 0000000000..f36aa3062d --- /dev/null +++ b/.github/scripts/autoupdate/build-kernel.sh @@ -0,0 +1,198 @@ +#!/usr/bin/env bash +# +# Build kernel to validate rebase +# +# This script must be run from within a linux-surface/kernel git repository. +# It will: +# 1. Validate the kernel source directory and version +# 2. Collect and merge kernel configs (base + surface + overrides) +# 3. Build the kernel and modules +# 4. Output metadata for subsequent steps +# +# Environment variables: +# KERNEL_VERSION: (required) Major.minor version (e.g., "6.18") +# LINUX_SURFACE_DIR: (required) Path to linux-surface repository + +set -euo pipefail + +# Enable debug mode if DEBUG is set +if [ "${DEBUG:-}" = "1" ]; then + set -x +fi + +# ============================================================================ +# Phase 1: Validation +# ============================================================================ + +echo "============================================" +echo "Kernel Build Validation Script" +echo "============================================" +echo "" + +if [ -z "${KERNEL_VERSION:-}" ]; then + echo "ERROR: KERNEL_VERSION environment variable is required" + echo "Example: KERNEL_VERSION=6.18" + exit 1 +fi + +if [ -z "${LINUX_SURFACE_DIR:-}" ]; then + echo "ERROR: LINUX_SURFACE_DIR environment variable is required" + echo "Example: LINUX_SURFACE_DIR=/path/to/linux-surface" + exit 1 +fi + +echo "[1/5] Validating environment..." + +# Verify we're in a git repository with kernel source +if ! git rev-parse --git-dir >/dev/null 2>&1; then + echo "ERROR: Not in a git repository" + echo "This script must be run from within the kernel repository" + exit 1 +fi + +# Verify this looks like a kernel source tree +if [ ! -f "Makefile" ] || [ ! -d "kernel" ] || [ ! -d "drivers" ]; then + echo "ERROR: Current directory doesn't appear to be a kernel source tree" + echo "Expected files: Makefile, kernel/, drivers/" + exit 1 +fi + +# Validate KERNEL_VERSION format +if ! echo "${KERNEL_VERSION}" | grep -qE '^[0-9]+\.[0-9]+$'; then + echo "ERROR: Invalid KERNEL_VERSION format: ${KERNEL_VERSION}" + echo "Expected format: X.Y (e.g., 6.18)" + exit 1 +fi + +# Validate LINUX_SURFACE_DIR exists +if [ ! -d "${LINUX_SURFACE_DIR}" ]; then + echo "ERROR: LINUX_SURFACE_DIR does not exist: ${LINUX_SURFACE_DIR}" + exit 1 +fi + +echo "Kernel version: ${KERNEL_VERSION}" +echo "Linux-surface dir: ${LINUX_SURFACE_DIR}" +echo "Validation successful" + +# ============================================================================ +# Phase 2: Config Setup +# ============================================================================ + +echo "[2/5] Setting up kernel configs..." + +# Define config paths +BASE_CONFIG="${LINUX_SURFACE_DIR}/.github/data/autoupdate/kernel-base.config" +SURFACE_CONFIG="${LINUX_SURFACE_DIR}/configs/surface-${KERNEL_VERSION}.config" +OVERRIDES_CONFIG="${LINUX_SURFACE_DIR}/.github/data/autoupdate/kernel-overrides.config" + +# Verify all required configs exist +if [ ! -f "${BASE_CONFIG}" ]; then + echo "ERROR: Base config not found: ${BASE_CONFIG}" + exit 1 +fi + +if [ ! -f "${SURFACE_CONFIG}" ]; then + echo "ERROR: Surface config not found for version ${KERNEL_VERSION}: ${SURFACE_CONFIG}" + echo "Available surface configs:" + ls -1 "${LINUX_SURFACE_DIR}/configs"/surface-*.config 2>/dev/null || echo "(none found)" + exit 1 +fi + +if [ ! -f "${OVERRIDES_CONFIG}" ]; then + echo "ERROR: Overrides config not found: ${OVERRIDES_CONFIG}" + exit 1 +fi + +echo "Base config: ${BASE_CONFIG}" +echo "Surface config: ${SURFACE_CONFIG}" +echo "Overrides config: ${OVERRIDES_CONFIG}" + +# Copy configs to kernel directory with simplified names +cp "${BASE_CONFIG}" base.config +cp "${SURFACE_CONFIG}" surface.config +cp "${OVERRIDES_CONFIG}" overrides.config + +echo "Configs copied successfully" + +# ============================================================================ +# Phase 3: Config Merge (Three-Stage) +# ============================================================================ + +echo "[3/5] Merging kernel configs..." + +# Merge configs using kernel's merge_config.sh script +# Order is critical: base → surface → overrides +if ! ./scripts/kconfig/merge_config.sh -m base.config surface.config overrides.config; then + echo "" + echo "ERROR: Config merge failed" + echo "Check the output above for details" + exit 1 +fi + +echo "Running olddefconfig to validate merged config..." + +if ! make olddefconfig; then + echo "" + echo "ERROR: olddefconfig failed" + echo "The merged config may have invalid options" + exit 1 +fi + +echo "Config merge successful" +echo "Final config: $(pwd)/.config" + +# ============================================================================ +# Phase 4: Build Kernel +# ============================================================================ + +echo "[4/5] Building kernel..." + +# Set KBUILD environment variables +export KBUILD_BUILD_HOST=github-actions +export KBUILD_BUILD_USER=linux-surface + +# Determine number of parallel jobs +NPROC=$(nproc) +echo "Building with ${NPROC} parallel jobs..." + +# Build kernel and modules +# Using 'all' target builds both vmlinux and modules +echo "Running: make -j${NPROC} all" + +if ! make -j"${NPROC}" all; then + echo "" + echo "============================================" + echo "BUILD FAILED" + echo "============================================" + echo "" + echo "The kernel build failed. This indicates the rebase introduced" + echo "compilation errors or config incompatibilities." + echo "" + echo "Check the build output above for error details." + echo "" + exit 1 +fi + +echo "" +echo "============================================" +echo "Build successful!" +echo "============================================" +echo "" + +# ============================================================================ +# Phase 5: Output Metadata +# ============================================================================ + +echo "[5/5] Setting outputs..." + +# Set outputs for GitHub Actions +if [ -n "${GITHUB_OUTPUT:-}" ]; then + echo "build_success=true" >> "${GITHUB_OUTPUT}" + echo "config_path=$(pwd)/.config" >> "${GITHUB_OUTPUT}" +fi + +echo "Build validation complete!" +echo "Config saved at: $(pwd)/.config" +echo "" + +echo "Done!" diff --git a/.github/scripts/autoupdate/rebase-kernel.sh b/.github/scripts/autoupdate/rebase-kernel.sh new file mode 100755 index 0000000000..b2f8f18ccf --- /dev/null +++ b/.github/scripts/autoupdate/rebase-kernel.sh @@ -0,0 +1,268 @@ +#!/usr/bin/env bash +# +# Rebase kernel branch onto upstream stable release +# +# This script must be run from within a linux-surface/kernel git repository. +# It will: +# 1. Detect the current base version using git describe +# 2. Add upstream remote (gregkh/linux) +# 3. Detect the latest stable tag for the same kernel version +# 4. Check if already up-to-date using git merge-base +# 5. Perform rebase onto the target tag +# 6. Output metadata for subsequent build/tag/push steps +# +# Environment variables: +# TARGET_TAG: (optional) Explicit target tag (e.g., "v6.18.5") +# If not specified, auto-detects latest stable for detected version + +set -euo pipefail + +# Enable debug mode if DEBUG is set +if [ "${DEBUG:-}" = "1" ]; then + set -x +fi + +# ============================================================================ +# Phase 1: Setup +# ============================================================================ + +echo "============================================" +echo "Kernel Branch Rebase Script" +echo "============================================" +echo "" + +# Verify we're in a git repository +if ! git rev-parse --git-dir >/dev/null 2>&1; then + echo "ERROR: Not in a git repository" + echo "This script must be run from within the kernel repository" + exit 1 +fi + +echo "[1/7] Configuring environment..." + +# Configuration +UPSTREAM_REPO="https://github.com/gregkh/linux" + +# Configure git identity for rebase operations +git config user.name "surfacebot" +git config user.email "surfacebot@users.noreply.github.com" + +echo "Environment configured" + +# ============================================================================ +# Phase 2: Add Upstream Remote +# ============================================================================ + +echo "[2/7] Adding upstream remote..." + +# Remove upstream remote if it already exists +if git remote get-url upstream >/dev/null 2>&1; then + echo "Upstream remote already exists, removing..." + git remote remove upstream +fi + +if ! git remote add upstream "${UPSTREAM_REPO}"; then + echo "ERROR: Failed to add upstream remote" + exit 1 +fi + +echo "Fetching upstream tags..." +if ! git fetch upstream --depth=500 --tags; then + echo "ERROR: Failed to fetch upstream tags" + exit 1 +fi + +echo "Successfully added and fetched upstream remote" + +# ============================================================================ +# Phase 3: Detect Current Base Version +# ============================================================================ + +echo "[3/7] Detecting current base version..." + +# Use git describe to find the current base version tag +# Pattern: v[0-9]*.[0-9]* matches vX.Y or vX.Y.Z (e.g., v6.18, v6.18.4, v7.0, v7.0.1) +CURRENT_BASE_VERSION=$(git describe --tags --match='v[0-9]*.[0-9]*' 2>/dev/null || true) + +if [ -z "${CURRENT_BASE_VERSION}" ]; then + echo "ERROR: Could not detect current base kernel version using git describe" + echo "Make sure the branch has proper version tags in its history" + exit 1 +fi + +echo "Current base version (git describe): ${CURRENT_BASE_VERSION}" + +# Extract just the version tag using grep +# This handles formats like: v6.18, v6.18.4, v6.18.4-123-gabcdef +CURRENT_BASE_TAG=$(echo "${CURRENT_BASE_VERSION}" | grep -oE 'v[0-9]+\.[0-9]+(\.[0-9]+)?' | head -1) + +if [ -z "${CURRENT_BASE_TAG}" ]; then + echo "ERROR: Could not extract version tag from: ${CURRENT_BASE_VERSION}" + exit 1 +fi + +echo "Current base tag: ${CURRENT_BASE_TAG}" + +# Extract kernel major.minor version from base tag (e.g., v6.18.4 → 6.18, v6.18 → 6.18) +KERNEL_VERSION=$(echo "${CURRENT_BASE_TAG}" | sed -E 's/^v([0-9]+\.[0-9]+)(\.[0-9]+)?$/\1/') + +if [ -z "${KERNEL_VERSION}" ]; then + echo "ERROR: Could not extract kernel version from tag: ${CURRENT_BASE_TAG}" + exit 1 +fi + +echo "Kernel version: ${KERNEL_VERSION}" + +# ============================================================================ +# Phase 4: Target Tag Detection +# ============================================================================ + +echo "[4/7] Detecting target tag..." + +# Check if TARGET_TAG was provided as input +if [ -n "${TARGET_TAG:-}" ]; then + echo "Using provided target tag: ${TARGET_TAG}" + + # Validate format (vX.Y or vX.Y.Z) + if ! echo "${TARGET_TAG}" | grep -qE '^v[0-9]+\.[0-9]+(\.[0-9]+)?$'; then + echo "ERROR: Invalid target tag format: ${TARGET_TAG}" + echo "Expected format: vX.Y or vX.Y.Z (e.g., v6.18, v6.18.4)" + exit 1 + fi + + # Extract version from provided tag to validate it matches detected kernel version + TAG_VERSION=$(echo "${TARGET_TAG}" | sed -E 's/^v([0-9]+\.[0-9]+)(\..*)?$/\1/') + + if [ "${TAG_VERSION}" != "${KERNEL_VERSION}" ]; then + echo "ERROR: Target tag version '${TAG_VERSION}' doesn't match detected kernel version '${KERNEL_VERSION}'" + exit 1 + fi + + # Verify the provided tag exists + if ! git rev-parse "${TARGET_TAG}" >/dev/null 2>&1; then + echo "ERROR: Provided target tag '${TARGET_TAG}' not found in repository" + exit 1 + fi +else + echo "Auto-detecting latest stable tag for version ${KERNEL_VERSION}..." + + # Find latest stable tag for same version + # Pattern: v${KERNEL_VERSION}.* matches v6.18.1, v6.18.4, etc. + # Filter out RC releases and sort by version + TARGET_TAG=$(git tag --list "v${KERNEL_VERSION}.*" \ + --sort=-version:refname | \ + grep -v '\-rc' | \ + head -1) + + if [ -z "${TARGET_TAG}" ]; then + echo "ERROR: No stable tags found for version ${KERNEL_VERSION}" + echo "Available tags:" + git tag --list "v${KERNEL_VERSION}.*" | head -10 + exit 1 + fi + + echo "Detected target tag: ${TARGET_TAG}" +fi + +# Extract full version from target tag (v6.18.4 → 6.18.4) +FULL_VERSION=$(echo "${TARGET_TAG}" | sed -E 's/^v(.*)$/\1/') + +if [ -z "${FULL_VERSION}" ]; then + echo "ERROR: Could not extract full version from target tag: ${TARGET_TAG}" + exit 1 +fi + +echo "Full version: ${FULL_VERSION}" + +# ============================================================================ +# Phase 5: Ancestor Check (Up-to-Date) +# ============================================================================ + +echo "[5/7] Checking if already up-to-date..." + +# Check if target tag is already an ancestor of HEAD +if git merge-base --is-ancestor "${TARGET_TAG}" HEAD; then + echo "" + echo "============================================" + echo "Already up-to-date!" + echo "============================================" + echo "Current branch already contains ${TARGET_TAG}" + echo "No rebase needed." + echo "" + + # Set outputs for GitHub Actions + if [ -n "${GITHUB_OUTPUT:-}" ]; then + echo "success=true" >> "${GITHUB_OUTPUT}" + echo "already_uptodate=true" >> "${GITHUB_OUTPUT}" + echo "target_tag=${TARGET_TAG}" >> "${GITHUB_OUTPUT}" + echo "kernel_version=${KERNEL_VERSION}" >> "${GITHUB_OUTPUT}" + echo "full_version=${FULL_VERSION}" >> "${GITHUB_OUTPUT}" + fi + + exit 0 +fi + +echo "Branch needs rebasing onto ${TARGET_TAG}" + +# ============================================================================ +# Phase 6: Perform Rebase +# ============================================================================ + +echo "[6/7] Performing rebase..." + +echo "Rebasing onto ${TARGET_TAG}..." + +# Perform the rebase +if ! git rebase "${TARGET_TAG}"; then + echo "" + echo "============================================" + echo "REBASE FAILED - CONFLICTS DETECTED" + echo "============================================" + echo "" + echo "The rebase encountered conflicts. Manual intervention required." + echo "" + echo "Conflicted files:" + git status --short | grep '^[UAD][UAD]' || echo "(see git status for details)" + echo "" + + # Abort the rebase + git rebase --abort + + echo "Rebase has been aborted." + echo "" + echo "To resolve manually:" + echo " 1. Clone the repository locally" + echo " 2. git checkout " + echo " 3. git rebase ${TARGET_TAG}" + echo " 4. Resolve conflicts" + echo " 5. git rebase --continue" + echo " 6. Force-push the result" + echo "" + + exit 1 +fi + +echo "Rebase completed successfully!" + +# ============================================================================ +# Phase 7: Output Metadata +# ============================================================================ + +echo "[7/7] Setting outputs..." + +# Set outputs for GitHub Actions +if [ -n "${GITHUB_OUTPUT:-}" ]; then + echo "success=true" >> "${GITHUB_OUTPUT}" + echo "already_uptodate=false" >> "${GITHUB_OUTPUT}" + echo "target_tag=${TARGET_TAG}" >> "${GITHUB_OUTPUT}" + echo "kernel_version=${KERNEL_VERSION}" >> "${GITHUB_OUTPUT}" + echo "full_version=${FULL_VERSION}" >> "${GITHUB_OUTPUT}" +fi + +echo "" +echo "============================================" +echo "Rebase complete!" +echo "============================================" +echo "Target tag: ${TARGET_TAG}" +echo "Kernel version: ${KERNEL_VERSION}" +echo "Full version: ${FULL_VERSION}" diff --git a/.github/workflows/rebase-kernel.yml b/.github/workflows/rebase-kernel.yml new file mode 100644 index 0000000000..3189226b69 --- /dev/null +++ b/.github/workflows/rebase-kernel.yml @@ -0,0 +1,184 @@ +name: Rebase and Build Kernel + +on: + # Manual trigger with inputs + workflow_dispatch: + inputs: + branch: + description: 'Kernel branch to rebase (e.g., "v6.18-surface")' + required: true + type: string + target_tag: + description: 'Target version tag (optional, e.g., "v6.18.5"). If not specified, auto-detected.' + required: false + type: string + dry_run: + description: 'Dry run mode - skip push and tag operations' + required: false + type: boolean + default: false + +# Prevent concurrent rebases of the same branch +concurrency: + group: rebase-kernel-${{ inputs.branch }} + cancel-in-progress: false + +jobs: + rebase-and-build: + name: Rebase and build ${{ inputs.branch }} + runs-on: ubuntu-latest + + steps: + - name: Maximize disk space + uses: easimon/maximize-build-space@master + with: + root-reserve-mb: 10240 # Reserve 10GB for build + remove-dotnet: true + remove-android: true + remove-docker-images: true + remove-haskell: true + + - name: Checkout linux-surface repo + uses: actions/checkout@v4 + with: + path: linux-surface + + - name: Clone kernel repository + env: + KERNEL_BRANCH: ${{ inputs.branch }} + run: | + git clone --depth=500 --branch="${KERNEL_BRANCH}" \ + https://github.com/linux-surface/kernel kernel + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + bc \ + bison \ + flex \ + libelf-dev \ + libssl-dev \ + libncurses-dev \ + kmod \ + cpio + + - name: Setup git identity + run: | + git config --global user.name "surfacebot" + git config --global user.email "surfacebot@users.noreply.github.com" + + - name: Rebase kernel + id: rebase + env: + TARGET_TAG: ${{ inputs.target_tag }} + working-directory: kernel + run: | + bash "${GITHUB_WORKSPACE}/linux-surface/.github/scripts/autoupdate/rebase-kernel.sh" + + - name: Build kernel + id: build + if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' + env: + KERNEL_VERSION: ${{ steps.rebase.outputs.kernel_version }} + LINUX_SURFACE_DIR: ${{ github.workspace }}/linux-surface + working-directory: kernel + run: | + bash "${GITHUB_WORKSPACE}/linux-surface/.github/scripts/autoupdate/build-kernel.sh" + + - name: Create tag + id: create_tag + if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' && steps.build.outputs.build_success == 'true' && inputs.dry_run == false + env: + FULL_VERSION: ${{ steps.rebase.outputs.full_version }} + working-directory: kernel + run: | + SURFACE_TAG="surface/v${FULL_VERSION}" + echo "Creating tag: ${SURFACE_TAG}" + git tag "${SURFACE_TAG}" + echo "surface_tag=${SURFACE_TAG}" >> "${GITHUB_OUTPUT}" + + - name: Push changes + if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' && steps.build.outputs.build_success == 'true' && inputs.dry_run == false + env: + KERNEL_BRANCH: ${{ inputs.branch }} + SURFACE_TAG: ${{ steps.create_tag.outputs.surface_tag }} + GITHUB_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + working-directory: kernel + run: | + # Configure git to use token authentication + git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/linux-surface/kernel.git" + + echo "Force-pushing branch ${KERNEL_BRANCH}..." + git push --force-with-lease origin "${KERNEL_BRANCH}" + + echo "Pushing tag ${SURFACE_TAG}..." + git push origin "${SURFACE_TAG}" + + echo "Pushing new upstream tags..." + git push origin "refs/tags/v*" + + - name: Upload kernel config artifact + if: steps.build.outputs.build_success == 'true' + uses: actions/upload-artifact@v4 + with: + name: kernel-config-${{ inputs.branch }}-${{ steps.rebase.outputs.target_tag }} + path: kernel/.config + retention-days: 30 + + - name: Generate summary + if: always() + env: + REBASE_SUCCESS: ${{ steps.rebase.outputs.success }} + ALREADY_UPTODATE: ${{ steps.rebase.outputs.already_uptodate }} + BUILD_SUCCESS: ${{ steps.build.outputs.build_success }} + KERNEL_BRANCH: ${{ inputs.branch }} + TARGET_TAG: ${{ steps.rebase.outputs.target_tag }} + FULL_VERSION: ${{ steps.rebase.outputs.full_version }} + DRY_RUN: ${{ inputs.dry_run }} + run: | + echo "## Kernel Rebase and Build Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${REBASE_SUCCESS}" = "true" ]; then + if [ "${ALREADY_UPTODATE}" = "true" ]; then + echo "✅ **Status:** Already up-to-date" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Branch \`${KERNEL_BRANCH}\` already contains target tag \`${TARGET_TAG}\`" >> $GITHUB_STEP_SUMMARY + echo "No rebase was necessary." >> $GITHUB_STEP_SUMMARY + elif [ "${BUILD_SUCCESS}" = "true" ]; then + echo "✅ **Status:** Success" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Branch:** \`${KERNEL_BRANCH}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Target tag:** \`${TARGET_TAG}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Full version:** \`${FULL_VERSION}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${DRY_RUN}" = "true" ]; then + echo "⚠️ **Dry run mode** - Changes were not pushed" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "To push the changes, run again with dry_run=false" >> $GITHUB_STEP_SUMMARY + else + echo "✅ Changes pushed successfully" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Next Steps" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Run the patch generation workflow to update patches:" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "Workflow: Generate Kernel Patches" >> $GITHUB_STEP_SUMMARY + echo " branch: ${KERNEL_BRANCH}" >> $GITHUB_STEP_SUMMARY + echo " base_version: ${TARGET_TAG}" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + fi + else + echo "❌ **Status:** Build failed" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Rebase succeeded but kernel build failed." >> $GITHUB_STEP_SUMMARY + echo "Check the build logs for errors." >> $GITHUB_STEP_SUMMARY + fi + else + echo "❌ **Status:** Rebase failed" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Check the rebase logs for conflict details." >> $GITHUB_STEP_SUMMARY + fi From eb86444046001f68011c89a482ce1024324ec6fd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 9 Jan 2026 01:23:24 +0100 Subject: [PATCH 168/236] .github/scripts/autoupdate/rebase-kernel: Do not fetch upstream here --- .github/scripts/autoupdate/rebase-kernel.sh | 59 ++++++--------------- .github/workflows/rebase-kernel.yml | 3 +- 2 files changed, 16 insertions(+), 46 deletions(-) diff --git a/.github/scripts/autoupdate/rebase-kernel.sh b/.github/scripts/autoupdate/rebase-kernel.sh index b2f8f18ccf..4ca33e88d2 100755 --- a/.github/scripts/autoupdate/rebase-kernel.sh +++ b/.github/scripts/autoupdate/rebase-kernel.sh @@ -1,15 +1,14 @@ #!/usr/bin/env bash # -# Rebase kernel branch onto upstream stable release +# Rebase kernel branch onto latest stable tag # # This script must be run from within a linux-surface/kernel git repository. # It will: # 1. Detect the current base version using git describe -# 2. Add upstream remote (gregkh/linux) -# 3. Detect the latest stable tag for the same kernel version -# 4. Check if already up-to-date using git merge-base -# 5. Perform rebase onto the target tag -# 6. Output metadata for subsequent build/tag/push steps +# 2. Detect the latest stable tag for the same kernel version +# 3. Check if already up-to-date using git merge-base +# 4. Perform rebase onto the target tag +# 5. Output metadata for subsequent build/tag/push steps # # Environment variables: # TARGET_TAG: (optional) Explicit target tag (e.g., "v6.18.5") @@ -38,10 +37,7 @@ if ! git rev-parse --git-dir >/dev/null 2>&1; then exit 1 fi -echo "[1/7] Configuring environment..." - -# Configuration -UPSTREAM_REPO="https://github.com/gregkh/linux" +echo "[1/6] Configuring environment..." # Configure git identity for rebase operations git config user.name "surfacebot" @@ -50,35 +46,10 @@ git config user.email "surfacebot@users.noreply.github.com" echo "Environment configured" # ============================================================================ -# Phase 2: Add Upstream Remote -# ============================================================================ - -echo "[2/7] Adding upstream remote..." - -# Remove upstream remote if it already exists -if git remote get-url upstream >/dev/null 2>&1; then - echo "Upstream remote already exists, removing..." - git remote remove upstream -fi - -if ! git remote add upstream "${UPSTREAM_REPO}"; then - echo "ERROR: Failed to add upstream remote" - exit 1 -fi - -echo "Fetching upstream tags..." -if ! git fetch upstream --depth=500 --tags; then - echo "ERROR: Failed to fetch upstream tags" - exit 1 -fi - -echo "Successfully added and fetched upstream remote" - -# ============================================================================ -# Phase 3: Detect Current Base Version +# Phase 2: Detect Current Base Version # ============================================================================ -echo "[3/7] Detecting current base version..." +echo "[2/6] Detecting current base version..." # Use git describe to find the current base version tag # Pattern: v[0-9]*.[0-9]* matches vX.Y or vX.Y.Z (e.g., v6.18, v6.18.4, v7.0, v7.0.1) @@ -114,10 +85,10 @@ fi echo "Kernel version: ${KERNEL_VERSION}" # ============================================================================ -# Phase 4: Target Tag Detection +# Phase 3: Target Tag Detection # ============================================================================ -echo "[4/7] Detecting target tag..." +echo "[3/6] Detecting target tag..." # Check if TARGET_TAG was provided as input if [ -n "${TARGET_TAG:-}" ]; then @@ -175,10 +146,10 @@ fi echo "Full version: ${FULL_VERSION}" # ============================================================================ -# Phase 5: Ancestor Check (Up-to-Date) +# Phase 4: Ancestor Check (Up-to-Date) # ============================================================================ -echo "[5/7] Checking if already up-to-date..." +echo "[4/6] Checking if already up-to-date..." # Check if target tag is already an ancestor of HEAD if git merge-base --is-ancestor "${TARGET_TAG}" HEAD; then @@ -208,7 +179,7 @@ echo "Branch needs rebasing onto ${TARGET_TAG}" # Phase 6: Perform Rebase # ============================================================================ -echo "[6/7] Performing rebase..." +echo "[5/6] Performing rebase..." echo "Rebasing onto ${TARGET_TAG}..." @@ -245,10 +216,10 @@ fi echo "Rebase completed successfully!" # ============================================================================ -# Phase 7: Output Metadata +# Phase 6: Output Metadata # ============================================================================ -echo "[7/7] Setting outputs..." +echo "[6/6] Setting outputs..." # Set outputs for GitHub Actions if [ -n "${GITHUB_OUTPUT:-}" ]; then diff --git a/.github/workflows/rebase-kernel.yml b/.github/workflows/rebase-kernel.yml index 3189226b69..fe11f1e5a3 100644 --- a/.github/workflows/rebase-kernel.yml +++ b/.github/workflows/rebase-kernel.yml @@ -47,8 +47,7 @@ jobs: env: KERNEL_BRANCH: ${{ inputs.branch }} run: | - git clone --depth=500 --branch="${KERNEL_BRANCH}" \ - https://github.com/linux-surface/kernel kernel + git clone --branch="${KERNEL_BRANCH}" https://github.com/linux-surface/kernel kernel - name: Install build dependencies run: | From e2245f8bcca97faeedb55e6c111923a03c8ee0ae Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 9 Jan 2026 01:36:33 +0100 Subject: [PATCH 169/236] .github/scripts/autoupdate/rebase-kernel: Use optimized checkout for kernel repo --- .github/workflows/rebase-kernel.yml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/rebase-kernel.yml b/.github/workflows/rebase-kernel.yml index fe11f1e5a3..832e734d96 100644 --- a/.github/workflows/rebase-kernel.yml +++ b/.github/workflows/rebase-kernel.yml @@ -39,15 +39,18 @@ jobs: remove-haskell: true - name: Checkout linux-surface repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: path: linux-surface - - name: Clone kernel repository - env: - KERNEL_BRANCH: ${{ inputs.branch }} - run: | - git clone --branch="${KERNEL_BRANCH}" https://github.com/linux-surface/kernel kernel + - name: Checkout kernel repository + uses: actions/checkout@v6 + with: + repository: linux-surface/kernel + path: kernel + ref: ${{ inputs.branch }} + fetch-depth: 0 + token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} - name: Install build dependencies run: | @@ -103,12 +106,8 @@ jobs: env: KERNEL_BRANCH: ${{ inputs.branch }} SURFACE_TAG: ${{ steps.create_tag.outputs.surface_tag }} - GITHUB_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} working-directory: kernel run: | - # Configure git to use token authentication - git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/linux-surface/kernel.git" - echo "Force-pushing branch ${KERNEL_BRANCH}..." git push --force-with-lease origin "${KERNEL_BRANCH}" From 684f6addbe8e6e868d98c52e59e4d45d0f7d24ce Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 9 Jan 2026 12:32:56 +0100 Subject: [PATCH 170/236] .github/scripts/autoupdate/rebase-kernel: Make building the kernel optional --- .github/workflows/rebase-kernel.yml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rebase-kernel.yml b/.github/workflows/rebase-kernel.yml index 832e734d96..dfdc1151cc 100644 --- a/.github/workflows/rebase-kernel.yml +++ b/.github/workflows/rebase-kernel.yml @@ -12,6 +12,11 @@ on: description: 'Target version tag (optional, e.g., "v6.18.5"). If not specified, auto-detected.' required: false type: string + build: + description: 'Build kernel to validate rebase' + required: false + type: boolean + default: true dry_run: description: 'Dry run mode - skip push and tag operations' required: false @@ -81,7 +86,7 @@ jobs: - name: Build kernel id: build - if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' + if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' && inputs.build == true env: KERNEL_VERSION: ${{ steps.rebase.outputs.kernel_version }} LINUX_SURFACE_DIR: ${{ github.workspace }}/linux-surface @@ -91,7 +96,7 @@ jobs: - name: Create tag id: create_tag - if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' && steps.build.outputs.build_success == 'true' && inputs.dry_run == false + if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' && (inputs.build == false || steps.build.outputs.build_success == 'true') && inputs.dry_run == false env: FULL_VERSION: ${{ steps.rebase.outputs.full_version }} working-directory: kernel @@ -102,7 +107,7 @@ jobs: echo "surface_tag=${SURFACE_TAG}" >> "${GITHUB_OUTPUT}" - name: Push changes - if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' && steps.build.outputs.build_success == 'true' && inputs.dry_run == false + if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' && (inputs.build == false || steps.build.outputs.build_success == 'true') && inputs.dry_run == false env: KERNEL_BRANCH: ${{ inputs.branch }} SURFACE_TAG: ${{ steps.create_tag.outputs.surface_tag }} @@ -130,6 +135,7 @@ jobs: env: REBASE_SUCCESS: ${{ steps.rebase.outputs.success }} ALREADY_UPTODATE: ${{ steps.rebase.outputs.already_uptodate }} + BUILD_ENABLED: ${{ inputs.build }} BUILD_SUCCESS: ${{ steps.build.outputs.build_success }} KERNEL_BRANCH: ${{ inputs.branch }} TARGET_TAG: ${{ steps.rebase.outputs.target_tag }} @@ -145,12 +151,19 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "Branch \`${KERNEL_BRANCH}\` already contains target tag \`${TARGET_TAG}\`" >> $GITHUB_STEP_SUMMARY echo "No rebase was necessary." >> $GITHUB_STEP_SUMMARY - elif [ "${BUILD_SUCCESS}" = "true" ]; then + elif [ "${BUILD_ENABLED}" = "false" ] || [ "${BUILD_SUCCESS}" = "true" ]; then echo "✅ **Status:** Success" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "- **Branch:** \`${KERNEL_BRANCH}\`" >> $GITHUB_STEP_SUMMARY echo "- **Target tag:** \`${TARGET_TAG}\`" >> $GITHUB_STEP_SUMMARY echo "- **Full version:** \`${FULL_VERSION}\`" >> $GITHUB_STEP_SUMMARY + + if [ "${BUILD_ENABLED}" = "false" ]; then + echo "- **Build:** Skipped" >> $GITHUB_STEP_SUMMARY + else + echo "- **Build:** Passed" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY if [ "${DRY_RUN}" = "true" ]; then From 5b7f9c44c391042064fdbadf31fc98edb261a0d6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 9 Jan 2026 13:35:08 +0100 Subject: [PATCH 171/236] .github/workflows: Add workflow to update kernel repo --- .github/workflows/sync-kernel-upstream.yml | 104 +++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 .github/workflows/sync-kernel-upstream.yml diff --git a/.github/workflows/sync-kernel-upstream.yml b/.github/workflows/sync-kernel-upstream.yml new file mode 100644 index 0000000000..aa911ec639 --- /dev/null +++ b/.github/workflows/sync-kernel-upstream.yml @@ -0,0 +1,104 @@ +name: Sync Kernel with Upstream + +on: + # Manual trigger + workflow_dispatch: + + # Automatic daily sync at 7:30 AM UTC + schedule: + - cron: '30 7 * * *' + +jobs: + sync: + name: Sync with upstream + runs-on: ubuntu-latest + + steps: + - name: Checkout kernel repository + uses: actions/checkout@v6 + with: + repository: linux-surface/kernel + path: kernel + fetch-depth: 0 + token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + + - name: Setup git identity + run: | + git config --global user.name "surfacebot" + git config --global user.email "surfacebot@users.noreply.github.com" + + - name: Sync with upstream + id: sync + working-directory: kernel + run: | + echo "Getting current origin tags..." + git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | grep -v '\^{}' | sort > /tmp/origin-tags.txt + + echo "Adding upstream remote..." + git remote add upstream https://github.com/gregkh/linux || true + + echo "Fetching from upstream..." + git fetch upstream --tags + + echo "Counting new tags..." + # Get tags that exist in upstream but not in origin + git ls-remote --tags upstream | awk '{print $2}' | sed 's|refs/tags/||' | grep -v '\^{}' | sort > /tmp/upstream-tags.txt + NEW_TAGS=$(comm -13 /tmp/origin-tags.txt /tmp/upstream-tags.txt | wc -l) + + echo "new_tags=${NEW_TAGS}" >> "${GITHUB_OUTPUT}" + echo "Found ${NEW_TAGS} new tags" + + # Show some of the new tags (first 10) + echo "Sample of new tags:" + comm -13 /tmp/origin-tags.txt /tmp/upstream-tags.txt 2>/dev/null | head -10 || true + + echo "Updating master branch..." + git checkout -B master origin/master + git merge --ff-only upstream/master || { + echo "ERROR: Cannot fast-forward master branch" + echo "Manual intervention may be required" + exit 1 + } + + echo "master_updated=true" >> "${GITHUB_OUTPUT}" + + - name: Push changes + if: steps.sync.outputs.new_tags != '0' || steps.sync.outputs.master_updated == 'true' + working-directory: kernel + run: | + echo "Pushing new tags..." + git push origin --tags + + echo "Pushing master branch..." + git push origin master + + - name: Generate summary + if: always() + env: + NEW_TAGS: ${{ steps.sync.outputs.new_tags }} + MASTER_UPDATED: ${{ steps.sync.outputs.master_updated }} + run: | + echo "## Kernel Upstream Sync Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${MASTER_UPDATED}" = "true" ]; then + echo "✅ **Status:** Success" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **New tags:** ${NEW_TAGS:-0}" >> $GITHUB_STEP_SUMMARY + echo "- **Master branch:** Updated" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${NEW_TAGS:-0}" -gt 0 ]; then + echo "### Next Steps" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "New kernel releases are available. Consider rebasing maintained branches:" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "Workflow: Rebase and Build Kernel" >> $GITHUB_STEP_SUMMARY + echo " branch: v6.18-surface (or other maintained branches)" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + fi + else + echo "ℹ️ **Status:** No changes" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Repository is already up-to-date with upstream." >> $GITHUB_STEP_SUMMARY + fi From 651f5a6ca38d682b80a91012753468393d546736 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 9 Jan 2026 14:16:10 +0100 Subject: [PATCH 172/236] .github/workflows/sync-kernel-upstream: Add support for caching kernel repo --- .github/workflows/sync-kernel-upstream.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/sync-kernel-upstream.yml b/.github/workflows/sync-kernel-upstream.yml index aa911ec639..bba4259ec3 100644 --- a/.github/workflows/sync-kernel-upstream.yml +++ b/.github/workflows/sync-kernel-upstream.yml @@ -14,6 +14,23 @@ jobs: runs-on: ubuntu-latest steps: + - name: Cache kernel repository + uses: actions/cache@v4 + with: + path: kernel/.git + key: kernel-git-${{ github.run_number }} + restore-keys: | + kernel-git- + + - name: Clean up old caches + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "Cleaning up old kernel-git caches (keeping only the latest)..." + gh cache list --repo ${{ github.repository }} --key kernel-git- --json id,key,createdAt --limit 100 | \ + jq -r 'sort_by(.createdAt) | reverse | .[1:] | .[].id' | \ + xargs -I {} gh cache delete {} --repo ${{ github.repository }} || true + - name: Checkout kernel repository uses: actions/checkout@v6 with: From 8925a22f0e9b6a7ba9117f215bf76a1ffcda06b6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 9 Jan 2026 14:44:37 +0100 Subject: [PATCH 173/236] .github/workflows/sync-kernel-upstream: Automatically trigger rebasing for maintained branches --- .../data/autoupdate/maintained-branches.conf | 10 ++ .github/workflows/sync-kernel-upstream.yml | 102 ++++++++++++++++-- 2 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 .github/data/autoupdate/maintained-branches.conf diff --git a/.github/data/autoupdate/maintained-branches.conf b/.github/data/autoupdate/maintained-branches.conf new file mode 100644 index 0000000000..7435574f39 --- /dev/null +++ b/.github/data/autoupdate/maintained-branches.conf @@ -0,0 +1,10 @@ +# Maintained kernel branches configuration +# Format: branch:version +# Example: v6.18-surface:6.18 +# +# The workflow will automatically trigger rebases when new stable tags +# matching the version are found (e.g., v6.18.5 for version 6.18) + +v6.18-surface:6.18 +v6.17-surface:6.17 +v6.12-surface:6.12 diff --git a/.github/workflows/sync-kernel-upstream.yml b/.github/workflows/sync-kernel-upstream.yml index bba4259ec3..d322f27a18 100644 --- a/.github/workflows/sync-kernel-upstream.yml +++ b/.github/workflows/sync-kernel-upstream.yml @@ -65,9 +65,12 @@ jobs: echo "new_tags=${NEW_TAGS}" >> "${GITHUB_OUTPUT}" echo "Found ${NEW_TAGS} new tags" + # Save new tags list for later processing + comm -13 /tmp/origin-tags.txt /tmp/upstream-tags.txt > /tmp/new-tags.txt + # Show some of the new tags (first 10) echo "Sample of new tags:" - comm -13 /tmp/origin-tags.txt /tmp/upstream-tags.txt 2>/dev/null | head -10 || true + cat /tmp/new-tags.txt | head -10 echo "Updating master branch..." git checkout -B master origin/master @@ -89,11 +92,81 @@ jobs: echo "Pushing master branch..." git push origin master + - name: Check for maintained branch updates + id: check_maintained + if: steps.sync.outputs.new_tags != '0' + run: | + CONFIG_FILE="${GITHUB_WORKSPACE}/linux-surface/.github/data/autoupdate/maintained-branches.conf" + + echo "Reading maintained branches from ${CONFIG_FILE}..." + + # Read config file, skip comments and empty lines + BRANCHES_TO_REBASE="" + + while IFS=: read -r BRANCH VERSION; do + # Skip comments and empty lines + [[ "$BRANCH" =~ ^#.*$ ]] && continue + [[ -z "$BRANCH" ]] && continue + + echo "Checking for version ${VERSION} (branch: ${BRANCH})..." + + # Check if any new tags match this version (e.g., v6.18.*, excluding -rc) + MATCHING_TAGS=$(grep -E "^v${VERSION}\.[0-9]+$" /tmp/new-tags.txt || true) + + if [ -n "$MATCHING_TAGS" ]; then + LATEST_TAG=$(echo "$MATCHING_TAGS" | sort -V | tail -1) + echo " ✓ Found new release for ${BRANCH}: ${LATEST_TAG}" + BRANCHES_TO_REBASE="${BRANCHES_TO_REBASE}${BRANCH}:${LATEST_TAG}," + else + echo " - No new releases for ${BRANCH}" + fi + done < "$CONFIG_FILE" + + # Remove trailing comma + BRANCHES_TO_REBASE="${BRANCHES_TO_REBASE%,}" + + echo "branches_to_rebase=${BRANCHES_TO_REBASE}" >> "${GITHUB_OUTPUT}" + + if [ -n "$BRANCHES_TO_REBASE" ]; then + echo "" + echo "Branches to rebase: ${BRANCHES_TO_REBASE}" + else + echo "" + echo "No maintained branches need rebasing" + fi + + - name: Trigger rebase workflows + if: steps.check_maintained.outputs.branches_to_rebase != '' + env: + GH_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + BRANCHES_TO_REBASE: ${{ steps.check_maintained.outputs.branches_to_rebase }} + run: | + echo "Triggering rebase workflows for updated branches..." + echo "" + + IFS=',' read -ra BRANCH_PAIRS <<< "$BRANCHES_TO_REBASE" + for pair in "${BRANCH_PAIRS[@]}"; do + BRANCH=$(echo "$pair" | cut -d: -f1) + TAG=$(echo "$pair" | cut -d: -f2) + + echo "Triggering rebase for ${BRANCH} to ${TAG}..." + gh workflow run rebase-kernel.yml \ + --repo ${{ github.repository }} \ + --field branch="${BRANCH}" \ + --field target_tag="${TAG}" \ + --field build=true \ + --field dry_run=false + + echo " ✓ Triggered" + echo "" + done + - name: Generate summary if: always() env: NEW_TAGS: ${{ steps.sync.outputs.new_tags }} MASTER_UPDATED: ${{ steps.sync.outputs.master_updated }} + BRANCHES_TO_REBASE: ${{ steps.check_maintained.outputs.branches_to_rebase }} run: | echo "## Kernel Upstream Sync Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY @@ -105,14 +178,27 @@ jobs: echo "- **Master branch:** Updated" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - if [ "${NEW_TAGS:-0}" -gt 0 ]; then - echo "### Next Steps" >> $GITHUB_STEP_SUMMARY + if [ -n "${BRANCHES_TO_REBASE}" ]; then + echo "### Automatic Rebases Triggered" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "The following branches will be automatically rebased:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + IFS=',' read -ra BRANCH_PAIRS <<< "$BRANCHES_TO_REBASE" + for pair in "${BRANCH_PAIRS[@]}"; do + BRANCH=$(echo "$pair" | cut -d: -f1) + TAG=$(echo "$pair" | cut -d: -f2) + echo "- **${BRANCH}** → ${TAG}" >> $GITHUB_STEP_SUMMARY + done + + echo "" >> $GITHUB_STEP_SUMMARY + echo "Check the [Rebase and Build Kernel workflow runs](../../actions/workflows/rebase-kernel.yml) for progress." >> $GITHUB_STEP_SUMMARY + elif [ "${NEW_TAGS:-0}" -gt 0 ]; then + echo "### New Tags" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "New tags were synced, but none match maintained branch versions." >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "New kernel releases are available. Consider rebasing maintained branches:" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - echo "Workflow: Rebase and Build Kernel" >> $GITHUB_STEP_SUMMARY - echo " branch: v6.18-surface (or other maintained branches)" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "To update maintained branches, edit \`.github/data/autoupdate/maintained-branches.txt\`" >> $GITHUB_STEP_SUMMARY fi else echo "ℹ️ **Status:** No changes" >> $GITHUB_STEP_SUMMARY From 202260a8334dce8283edcc8594ce769b38aafa5a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 9 Jan 2026 14:48:31 +0100 Subject: [PATCH 174/236] .github/workflows/rebase-kernel: Automatically trigger patch generation --- .github/workflows/rebase-kernel.yml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rebase-kernel.yml b/.github/workflows/rebase-kernel.yml index dfdc1151cc..8f13b01ee7 100644 --- a/.github/workflows/rebase-kernel.yml +++ b/.github/workflows/rebase-kernel.yml @@ -130,6 +130,22 @@ jobs: path: kernel/.config retention-days: 30 + - name: Trigger patch generation + if: steps.rebase.outputs.success == 'true' && steps.rebase.outputs.already_uptodate != 'true' && (inputs.build == false || steps.build.outputs.build_success == 'true') && inputs.dry_run == false + env: + GH_TOKEN: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + KERNEL_BRANCH: ${{ inputs.branch }} + TARGET_TAG: ${{ steps.rebase.outputs.target_tag }} + run: | + echo "Triggering patch generation for ${KERNEL_BRANCH}..." + + gh workflow run generate-patches.yml \ + --repo ${{ github.repository }} \ + --field branch="${KERNEL_BRANCH}" \ + --field base_version="${TARGET_TAG}" + + echo "✓ Patch generation workflow triggered" + - name: Generate summary if: always() env: @@ -173,14 +189,11 @@ jobs: else echo "✅ Changes pushed successfully" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "### Next Steps" >> $GITHUB_STEP_SUMMARY + echo "### Automatic Patch Generation" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Patch generation workflow has been automatically triggered." >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "Run the patch generation workflow to update patches:" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - echo "Workflow: Generate Kernel Patches" >> $GITHUB_STEP_SUMMARY - echo " branch: ${KERNEL_BRANCH}" >> $GITHUB_STEP_SUMMARY - echo " base_version: ${TARGET_TAG}" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "Check the [Generate Kernel Patches workflow runs](../../actions/workflows/generate-patches.yml) for progress." >> $GITHUB_STEP_SUMMARY fi else echo "❌ **Status:** Build failed" >> $GITHUB_STEP_SUMMARY From 7ab49101c993a5100d0b97860ae93215ab338650 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Fri, 9 Jan 2026 14:09:26 +0000 Subject: [PATCH 175/236] patches/v6.18: Update to v6.18.4 Generated 16 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.4 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 10 +-- patches/6.18/0002-surface3.patch | 12 ++-- patches/6.18/0003-mwifiex.patch | 22 +++---- patches/6.18/0004-ath10k.patch | 4 +- patches/6.18/0005-ipts.patch | 68 ++++++++++---------- patches/6.18/0006-ithc.patch | 42 ++++++------ patches/6.18/0007-surface-sam.patch | 12 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 12 ++-- patches/6.18/0009-surface-button.patch | 8 +-- patches/6.18/0010-surface-typecover.patch | 12 ++-- patches/6.18/0011-surface-shutdown.patch | 12 ++-- patches/6.18/0012-surface-gpe.patch | 4 +- patches/6.18/0013-cameras.patch | 52 +++++++-------- patches/6.18/0014-amd-gpio.patch | 8 +-- patches/6.18/0015-rtc.patch | 4 +- patches/6.18/0016-hid-surface.patch | 12 ++-- 16 files changed, 147 insertions(+), 147 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 6b7059c6e3..8d2f4e545a 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 25a3cacb23bd76c57052e9d33ddc39b457ae2c28 Mon Sep 17 00:00:00 2001 +From b0e0398f4f468ece3c20371fe1c7d12d5b168140 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -17,7 +17,7 @@ Patchset: secureboot 1 file changed, 4 insertions(+) diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index 9bea5a1e2c52..25848f886ad6 100644 +index 9bea5a1e2..25848f886 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -111,7 +111,11 @@ extra_header_fields: @@ -35,7 +35,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 -- 2.52.0 -From de4f7cfd4e2b7a538eb11a7adc8619af3af51d5c Mon Sep 17 00:00:00 2001 +From 9b9d346c25feaab026a21b9e430d42c9dbc70215 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 6c42061ca20e..f7cb5669b5fb 100644 +index 6c42061ca..f7cb5669b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3342,6 +3342,11 @@ @@ -69,7 +69,7 @@ index 6c42061ca20e..f7cb5669b5fb 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 26e45f86b955..8ec46d4565a0 100644 +index 26e45f86b..8ec46d456 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -38,6 +38,7 @@ diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index b34a30c742..79ba196eee 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From cd774dcb0460ea32fa5fb5f68bf1842ff16785a9 Mon Sep 17 00:00:00 2001 +From 87c2e72e7547137bd0a22818208c26640526c59f Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -40,7 +40,7 @@ Patchset: surface3 3 files changed, 24 insertions(+) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index 6c8fb7a4dde4..22797a53f4d8 100644 +index 6c8fb7a4d..22797a53f 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { @@ -58,7 +58,7 @@ index 6c8fb7a4dde4..22797a53f4d8 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 29a403526cd9..986f32132c3d 100644 +index 29a403526..986f32132 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3792,6 +3792,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -78,7 +78,7 @@ index 29a403526cd9..986f32132c3d 100644 /* * Match for the GPDwin which unfortunately uses somewhat diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0c28..0b930c91bccb 100644 +index e4c3492a0..0b930c91b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.52.0 -From 81f6b6fe5b65630bf1ede3bd312011feb7c5a5f6 Mon Sep 17 00:00:00 2001 +From 2b85458ab9beb7f81618c5a71e4446be86850d89 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -179,7 +179,7 @@ Patchset: surface3 1 file changed, 26 insertions(+) diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c -index 6074b7730e86..6aa3e1d6f160 100644 +index 6074b7730..6aa3e1d6f 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -25,6 +25,12 @@ diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 569a9ae739..b6f806bccb 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 2fd01f55dca7bcb79337d8d5b634220eefe8d94b Mon Sep 17 00:00:00 2001 +From a10a3d9a31c5fdd5748f796dd02787bbdcc219ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -32,7 +32,7 @@ Patchset: mwifiex 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index a760de191fce..db9b203226a8 100644 +index a760de191..db9b20322 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) @@ -58,7 +58,7 @@ index a760de191fce..db9b203226a8 100644 mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 +index dd6d21f1d..f46b06f8d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -151,7 +151,7 @@ index dd6d21f1dbfd..f46b06f8d643 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 +index d6ff964ae..5d30ae39d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -4,6 +4,7 @@ @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.52.0 -From c365824e93d36158f175f6a4d0d44187b1581c19 Mon Sep 17 00:00:00 2001 +From 3f5365b05fcaa1e9a01ddbd1b4fbfb3cf13ed6b8 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -187,7 +187,7 @@ Patchset: mwifiex 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index db9b203226a8..ffd0c1fe9223 100644 +index db9b20322..ffd0c1fe9 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, @@ -212,7 +212,7 @@ index db9b203226a8..ffd0c1fe9223 100644 } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 +index f46b06f8d..99b024ecb 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -306,7 +306,7 @@ index f46b06f8d643..99b024ecbade 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 +index 5d30ae39d..c14eb56eb 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -5,6 +5,7 @@ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.52.0 -From a880e786693cfd209e5995d8ad37741d2be37d0f Mon Sep 17 00:00:00 2001 +From ac70d7580b1d368d2a2174ad7c9165fdd2cf37de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index b92bfd131567..4899dc2bb490 100644 +index 3420f711f..50362656f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index b92bfd131567..4899dc2bb490 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4188,6 +4190,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4192,6 +4194,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index 822827362f..5bcd7f13f5 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From de159f5dda4408ed6227313e95aa80457b9a888a Mon Sep 17 00:00:00 2001 +From b7fa0d87576307a4525d8f047e8efacab66df2ca Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 9ae3595fb698..b26a39c97998 100644 +index 9ae3595fb..b26a39c97 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -41,6 +41,9 @@ static bool fw_diag_log; diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index e2253bcaf8..3d659c8d56 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 39c4ce6999998717128ece65117ebaa151ff6032 Mon Sep 17 00:00:00 2001 +From 22c4f1b753aa6f381bc367bf16f4bed0b8187386 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index a4f75dc36929..e4a561b257d7 100644 +index a4f75dc36..e4a561b25 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index a4f75dc36929..e4a561b257d7 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 73cad914be9f..807e352af059 100644 +index 73cad914b..807e352af 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -37,7 +37,7 @@ index 73cad914be9f..807e352af059 100644 -- 2.52.0 -From 8df324adc035358f6a5d4dbb0dc0816c4d706d44 Mon Sep 17 00:00:00 2001 +From 34ac5358779ab71f9ee1c0d831842473a0579231 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index e236c7ec221f..9e31a5fe1f66 100644 +index e236c7ec2..9e31a5fe1 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -144,7 +144,7 @@ index e236c7ec221f..9e31a5fe1f66 100644 -- 2.52.0 -From 4fbea7826d9bb3ee99d3483bc1dd35cca93abf13 Mon Sep 17 00:00:00 2001 +From 7a787a4d3d3173955c241673f365333a71748949 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,7 +211,7 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 04420a713be0..63b4eda94db2 100644 +index 04420a713..63b4eda94 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1439,6 +1439,8 @@ source "drivers/hid/surface-hid/Kconfig" @@ -224,7 +224,7 @@ index 04420a713be0..63b4eda94db2 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 361a7daedeb8..b73a1bbd3a1d 100644 +index 361a7daed..b73a1bbd3 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -176,3 +176,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -235,7 +235,7 @@ index 361a7daedeb8..b73a1bbd3a1d 100644 +obj-$(CONFIG_HID_IPTS) += ipts/ diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 000000000000..297401bd388d +index 000000000..297401bd3 --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -255,7 +255,7 @@ index 000000000000..297401bd388d + module will be called ipts. diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile new file mode 100644 -index 000000000000..883896f68e6a +index 000000000..883896f68 --- /dev/null +++ b/drivers/hid/ipts/Makefile @@ -0,0 +1,16 @@ @@ -277,7 +277,7 @@ index 000000000000..883896f68e6a +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 000000000000..63a4934bbc5f +index 000000000..63a4934bb --- /dev/null +++ b/drivers/hid/ipts/cmd.c @@ -0,0 +1,61 @@ @@ -344,7 +344,7 @@ index 000000000000..63a4934bbc5f +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 000000000000..2b4079075b64 +index 000000000..2b4079075 --- /dev/null +++ b/drivers/hid/ipts/cmd.h @@ -0,0 +1,60 @@ @@ -410,7 +410,7 @@ index 000000000000..2b4079075b64 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 000000000000..ba33259f1f7c +index 000000000..ba33259f1 --- /dev/null +++ b/drivers/hid/ipts/context.h @@ -0,0 +1,52 @@ @@ -468,7 +468,7 @@ index 000000000000..ba33259f1f7c +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 000000000000..5360842d260b +index 000000000..5360842d2 --- /dev/null +++ b/drivers/hid/ipts/control.c @@ -0,0 +1,486 @@ @@ -960,7 +960,7 @@ index 000000000000..5360842d260b +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 000000000000..26629c5144ed +index 000000000..26629c514 --- /dev/null +++ b/drivers/hid/ipts/control.h @@ -0,0 +1,126 @@ @@ -1092,7 +1092,7 @@ index 000000000000..26629c5144ed +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 000000000000..307438c7c80c +index 000000000..307438c7c --- /dev/null +++ b/drivers/hid/ipts/desc.h @@ -0,0 +1,80 @@ @@ -1178,7 +1178,7 @@ index 000000000000..307438c7c80c +#endif /* IPTS_DESC_H */ diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 000000000000..7b9f54388a9f +index 000000000..7b9f54388 --- /dev/null +++ b/drivers/hid/ipts/eds1.c @@ -0,0 +1,104 @@ @@ -1288,7 +1288,7 @@ index 000000000000..7b9f54388a9f +} diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h new file mode 100644 -index 000000000000..eeeb6575e3e8 +index 000000000..eeeb6575e --- /dev/null +++ b/drivers/hid/ipts/eds1.h @@ -0,0 +1,35 @@ @@ -1329,7 +1329,7 @@ index 000000000000..eeeb6575e3e8 + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c new file mode 100644 -index 000000000000..639940794615 +index 000000000..639940794 --- /dev/null +++ b/drivers/hid/ipts/eds2.c @@ -0,0 +1,145 @@ @@ -1480,7 +1480,7 @@ index 000000000000..639940794615 +} diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h new file mode 100644 -index 000000000000..064e3716907a +index 000000000..064e37169 --- /dev/null +++ b/drivers/hid/ipts/eds2.h @@ -0,0 +1,35 @@ @@ -1521,7 +1521,7 @@ index 000000000000..064e3716907a + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c new file mode 100644 -index 000000000000..e34a1a4f9fa7 +index 000000000..e34a1a4f9 --- /dev/null +++ b/drivers/hid/ipts/hid.c @@ -0,0 +1,225 @@ @@ -1752,7 +1752,7 @@ index 000000000000..e34a1a4f9fa7 +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 000000000000..1ebe77447903 +index 000000000..1ebe77447 --- /dev/null +++ b/drivers/hid/ipts/hid.h @@ -0,0 +1,24 @@ @@ -1782,7 +1782,7 @@ index 000000000000..1ebe77447903 +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 000000000000..fb5b5c13ee3e +index 000000000..fb5b5c13e --- /dev/null +++ b/drivers/hid/ipts/main.c @@ -0,0 +1,126 @@ @@ -1914,7 +1914,7 @@ index 000000000000..fb5b5c13ee3e +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 000000000000..1e0395ceae4a +index 000000000..1e0395cea --- /dev/null +++ b/drivers/hid/ipts/mei.c @@ -0,0 +1,188 @@ @@ -2108,7 +2108,7 @@ index 000000000000..1e0395ceae4a +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 000000000000..973bade6b0fd +index 000000000..973bade6b --- /dev/null +++ b/drivers/hid/ipts/mei.h @@ -0,0 +1,66 @@ @@ -2180,7 +2180,7 @@ index 000000000000..973bade6b0fd +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 000000000000..977724c728c3 +index 000000000..977724c72 --- /dev/null +++ b/drivers/hid/ipts/receiver.c @@ -0,0 +1,251 @@ @@ -2437,7 +2437,7 @@ index 000000000000..977724c728c3 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 000000000000..3de7da62d40c +index 000000000..3de7da62d --- /dev/null +++ b/drivers/hid/ipts/receiver.h @@ -0,0 +1,16 @@ @@ -2459,7 +2459,7 @@ index 000000000000..3de7da62d40c +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 000000000000..cc14653b2a9f +index 000000000..cc14653b2 --- /dev/null +++ b/drivers/hid/ipts/resources.c @@ -0,0 +1,131 @@ @@ -2596,7 +2596,7 @@ index 000000000000..cc14653b2a9f +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 000000000000..2068e13285f0 +index 000000000..2068e1328 --- /dev/null +++ b/drivers/hid/ipts/resources.h @@ -0,0 +1,41 @@ @@ -2643,7 +2643,7 @@ index 000000000000..2068e13285f0 +#endif /* IPTS_RESOURCES_H */ diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h new file mode 100644 -index 000000000000..e8dd98895a7e +index 000000000..e8dd98895 --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -2749,7 +2749,7 @@ index 000000000000..e8dd98895a7e +#endif /* IPTS_SPEC_DATA_H */ diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h new file mode 100644 -index 000000000000..41845f9d9025 +index 000000000..41845f9d9 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h @@ -0,0 +1,290 @@ @@ -3045,7 +3045,7 @@ index 000000000000..41845f9d9025 +#endif /* IPTS_SPEC_DEVICE_H */ diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h new file mode 100644 -index 000000000000..5a58d4a0a610 +index 000000000..5a58d4a0a --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h @@ -0,0 +1,34 @@ @@ -3085,7 +3085,7 @@ index 000000000000..5a58d4a0a610 +#endif /* IPTS_SPEC_HID_H */ diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c new file mode 100644 -index 000000000000..355e92bea26f +index 000000000..355e92bea --- /dev/null +++ b/drivers/hid/ipts/thread.c @@ -0,0 +1,84 @@ @@ -3175,7 +3175,7 @@ index 000000000000..355e92bea26f +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 000000000000..1f966b8b32c4 +index 000000000..1f966b8b3 --- /dev/null +++ b/drivers/hid/ipts/thread.h @@ -0,0 +1,59 @@ diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index c6093f21e5..964f830dd6 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From 128847caa31eebe781584112d55f7a97fbbaff5c Mon Sep 17 00:00:00 2001 +From ccbd80a1526b82e7f76cc1808775ed952fce90f1 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,7 +10,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 8bcbfe3d9c72..c78806d35f2b 100644 +index 8bcbfe3d9..c78806d35 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) @@ -39,7 +39,7 @@ index 8bcbfe3d9c72..c78806d35f2b 100644 -- 2.52.0 -From 28652a8c89b32522a705b93661a5bf00412a012a Mon Sep 17 00:00:00 2001 +From 3e9189b92d72fc0859c39687794f55b36e270c6c Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,7 +86,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 63b4eda94db2..184a2b2f9347 100644 +index 63b4eda94..184a2b2f9 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1441,6 +1441,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" @@ -99,7 +99,7 @@ index 63b4eda94db2..184a2b2f9347 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index b73a1bbd3a1d..3190ece25626 100644 +index b73a1bbd3..3190ece25 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -178,3 +178,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ @@ -109,7 +109,7 @@ index b73a1bbd3a1d..3190ece25626 100644 +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 000000000000..4937ba131297 +index 000000000..4937ba131 --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -121,7 +121,7 @@ index 000000000000..4937ba131297 + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 000000000000..ede713023609 +index 000000000..ede713023 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -139,7 +139,7 @@ index 000000000000..ede713023609 + module will be called ithc. diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c new file mode 100644 -index 000000000000..2d8c6afe9966 +index 000000000..2d8c6afe9 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,149 @@ @@ -294,7 +294,7 @@ index 000000000000..2d8c6afe9966 + diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h new file mode 100644 -index 000000000000..38c53d916bdb +index 000000000..38c53d916 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.h @@ -0,0 +1,7 @@ @@ -307,7 +307,7 @@ index 000000000000..38c53d916bdb + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 000000000000..bf4eab33062b +index 000000000..bf4eab330 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,312 @@ @@ -625,7 +625,7 @@ index 000000000000..bf4eab33062b + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 000000000000..1749a5819b3e +index 000000000..1749a5819 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,47 @@ @@ -678,7 +678,7 @@ index 000000000000..1749a5819b3e + diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c new file mode 100644 -index 000000000000..065646ab499e +index 000000000..065646ab4 --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.c @@ -0,0 +1,207 @@ @@ -891,7 +891,7 @@ index 000000000000..065646ab499e + diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h new file mode 100644 -index 000000000000..599eb912c8c8 +index 000000000..599eb912c --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.h @@ -0,0 +1,32 @@ @@ -929,7 +929,7 @@ index 000000000000..599eb912c8c8 + diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c new file mode 100644 -index 000000000000..8883987fb352 +index 000000000..8883987fb --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.c @@ -0,0 +1,254 @@ @@ -1189,7 +1189,7 @@ index 000000000000..8883987fb352 + diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h new file mode 100644 -index 000000000000..28d692462072 +index 000000000..28d692462 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.h @@ -0,0 +1,8 @@ @@ -1203,7 +1203,7 @@ index 000000000000..28d692462072 + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000000..094d878d671b +index 000000000..094d878d6 --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,438 @@ @@ -1647,7 +1647,7 @@ index 000000000000..094d878d671b + diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c new file mode 100644 -index 000000000000..e2d1690b8cf8 +index 000000000..e2d1690b8 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.c @@ -0,0 +1,607 @@ @@ -2260,7 +2260,7 @@ index 000000000000..e2d1690b8cf8 + diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h new file mode 100644 -index 000000000000..74d882f6b2f0 +index 000000000..74d882f6b --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.h @@ -0,0 +1,39 @@ @@ -2305,7 +2305,7 @@ index 000000000000..74d882f6b2f0 + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 000000000000..c0f13506af20 +index 000000000..c0f13506a --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,154 @@ @@ -2465,7 +2465,7 @@ index 000000000000..c0f13506af20 + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 000000000000..4f541fe533fa +index 000000000..4f541fe53 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,211 @@ @@ -2682,7 +2682,7 @@ index 000000000000..4f541fe533fa + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 000000000000..aec320d4e945 +index 000000000..aec320d4e --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,89 @@ diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index 4e669edfd4..c598f19f20 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From e8e5de942e8dae7826866ab63d687071bf4e08fd Mon Sep 17 00:00:00 2001 +From 341b34d9fbf0bf7351f2dc481a2acf5e5076829b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -14,7 +14,7 @@ Patchset: surface-sam create mode 100644 drivers/rtc/rtc-surface.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 2933c41c77c8..050eba74d8a2 100644 +index 2933c41c7..050eba74d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1399,6 +1399,13 @@ config RTC_DRV_NTXEC @@ -32,7 +32,7 @@ index 2933c41c77c8..050eba74d8a2 100644 config RTC_DRV_ASM9260 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile -index 8221bda6e6dc..8932df6e03ed 100644 +index 8221bda6e..8932df6e0 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -183,6 +183,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o @@ -45,7 +45,7 @@ index 8221bda6e6dc..8932df6e03ed 100644 obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c new file mode 100644 -index 000000000000..f6c17c4e98d5 +index 000000000..f6c17c4e9 --- /dev/null +++ b/drivers/rtc/rtc-surface.c @@ -0,0 +1,129 @@ @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.52.0 -From 49dfbe3512bb85eb4fe49a6998151fac777ee74c Mon Sep 17 00:00:00 2001 +From 2971c838857dcd170848a1f655b06a26f2b3541f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -193,7 +193,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index a594d5fcfcfd..07b03aa4fa7f 100644 +index a594d5fcf..07b03aa4f 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 6a10a2c9b6..dedf78a483 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 342de48e39eb9303d8044da0c4a5dbe509583cfc Mon Sep 17 00:00:00 2001 +From 7ecd3735e92ad10f072ea5755e30aa70f1de04fb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,7 +55,7 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index ed90858a27b7..070c36637811 100644 +index ed90858a2..070c36637 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, @@ -109,7 +109,7 @@ index ed90858a27b7..070c36637811 100644 -- 2.52.0 -From 73a2034c5dfb1e594d2b8532cfa8deedf4c09dc0 Mon Sep 17 00:00:00 2001 +From 497dd96a69fac182bc2f1dc110ec32789839deee Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -132,7 +132,7 @@ Patchset: surface-sam-over-hid create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index f775c6ca1ec1..2075e3852053 100644 +index f775c6ca1..2075e3852 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH @@ -150,7 +150,7 @@ index f775c6ca1ec1..2075e3852053 100644 tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 +index 533443309..7efcd0cdb 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o @@ -163,7 +163,7 @@ index 53344330939b..7efcd0cdb532 100644 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 000000000000..68db237734a1 +index 000000000..68db23773 --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c @@ -0,0 +1,136 @@ diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 4319f53b25..76969c2e1d 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 8fc811e764ac2db7d7f3e4ec5620778d00af5490 Mon Sep 17 00:00:00 2001 +From 66db0bcac62218421b6ed1662f2688933dab48f4 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -20,7 +20,7 @@ Patchset: surface-button 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index b8cad415c62c..43b5d56383e3 100644 +index b8cad415c..43b5d5638 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.52.0 -From b356c8c66cbdcf6cbf0872cb45a09bb80f95ba77 Mon Sep 17 00:00:00 2001 +From b051f52f5fe5748b4877f73b81f91d38a5033c1c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -96,7 +96,7 @@ Patchset: surface-button 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 +index 2755601f9..4240c98ca 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index 469ae06840..90eb86c91a 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From a317e20b19b8f0abd0afc2fb1abc4359346bd9bf Mon Sep 17 00:00:00 2001 +From 8e7a306e02f3631bb15804dcacc372dc4ee28406 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 47f589c4104a..6b00aec67ee2 100644 +index 47f589c41..6b00aec67 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -39,7 +39,7 @@ index 47f589c4104a..6b00aec67ee2 100644 -- 2.52.0 -From e6305ccb279e30c5fe2848e4fb5cedef2d2c81d4 Mon Sep 17 00:00:00 2001 +From 8b8670b3421cb324331011f714df157ec658844a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 179dc316b4b5..7d644e1c445e 100644 +index 179dc316b..7d644e1c4 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -274,7 +274,7 @@ index 179dc316b4b5..7d644e1c445e 100644 -- 2.52.0 -From 95603cd2fe1581f1131e4e5300f0a02a2bf146c1 Mon Sep 17 00:00:00 2001 +From 3bb9c674792795fe54da7901bfc638daffdf9446 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 7d644e1c445e..0eb4f7d1228e 100644 +index 7d644e1c4..0eb4f7d12 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -81,6 +81,7 @@ MODULE_LICENSE("GPL"); diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index f0da8b635c..f06466020d 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 790ea29fa1c48f6ff4cf5bda8ce549c8ee5a740a Mon Sep 17 00:00:00 2001 +From bab8498e8af2474d85f8a6c3f8396dbf9dbf8d2e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 302d61783f6c..4a8a08bd92dd 100644 +index 327b21c48..51dd5e10f 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,7 +37,7 @@ index 302d61783f6c..4a8a08bd92dd 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index b9c252aa6fe0..ce4c0da99537 100644 +index b9c252aa6..ce4c0da99 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6341,3 +6341,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) @@ -81,7 +81,7 @@ index b9c252aa6fe0..ce4c0da99537 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index bf97d49c23cf..90eead93d825 100644 +index bf97d49c2..90eead93d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -487,6 +487,7 @@ struct pci_dev { @@ -95,7 +95,7 @@ index bf97d49c23cf..90eead93d825 100644 -- 2.52.0 -From a4f65698937823a5e3210932c52640ac2115837e Mon Sep 17 00:00:00 2001 +From 1afc88118fa7014d5d6ef99c48d14468393ad422 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops @@ -108,7 +108,7 @@ Patchset: surface-shutdown 1 file changed, 13 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index ce4c0da99537..fdc410bf70e5 100644 +index ce4c0da99..fdc410bf7 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6360,6 +6360,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index 4d2f11676a..e7dd74892a 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 21cc80c64c4e7e19cf84311dcc6ecaee4992e03b Mon Sep 17 00:00:00 2001 +From cec5167e48fe6afb38dd75cf6f0f700566313267 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -12,7 +12,7 @@ Patchset: surface-gpe 1 file changed, 17 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index b359413903b1..b4496db79f39 100644 +index b35941390..b4496db79 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index b9c5ba715f..6fe0ce61a8 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From cefa9f598d93854ddcfa9cbe9ac4037302aaa3bf Mon Sep 17 00:00:00 2001 +From 1b27298c89877c41dbcc314443d75fe910e22853 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,7 +58,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index ef16d58b2949..a6bad2679a0c 100644 +index ef16d58b2..a6bad2679 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, @@ -74,7 +74,7 @@ index ef16d58b2949..a6bad2679a0c 100644 -- 2.52.0 -From 8342d01a60e39e5b4d63676a1cb18bab6207974a Mon Sep 17 00:00:00 2001 +From 877aeb2d25ada1c118875cfdb3729693f35c5ff4 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 9e31a5fe1f66..bdd32551c452 100644 +index 9e31a5fe1..bdd32551c 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -184,7 +184,7 @@ index 9e31a5fe1f66..bdd32551c452 100644 -- 2.52.0 -From 31367eafab6cb5efba28fcf10b0aadc232f20041 Mon Sep 17 00:00:00 2001 +From 3234b69803a65f71309184b4c041e35f3d23eaf9 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -201,7 +201,7 @@ Patchset: cameras 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 0133405697dc..9e0763bdc758 100644 +index 013340569..9e0763bdc 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.52.0 -From 274297ffcb3d62e37c70cd0253ad1337f7e4309b Mon Sep 17 00:00:00 2001 +From a3471b5fa576339b79789e4894511d8577034ae8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -236,7 +236,7 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 27afc3fc0175..28b192c9a5ec 100644 +index 27afc3fc0..28b192c9a 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) @@ -260,7 +260,7 @@ index 27afc3fc0175..28b192c9a5ec 100644 -- 2.52.0 -From 3dd814b0a0cea2567fdd4cd8eb4588e9c2d7cac6 Mon Sep 17 00:00:00 2001 +From f1cd3e354b93cf64d376d05bbd8eaf6dc5ba599c Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -279,7 +279,7 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index ee884a8221fb..4f6bafd900ee 100644 +index ee884a822..4f6bafd90 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) @@ -294,7 +294,7 @@ index ee884a8221fb..4f6bafd900ee 100644 * No reference taken. The reference is held by the device (struct * v4l2_subdev.dev), and async sub-device does not exist independently diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index cb153ce42c45..f11b499e14bb 100644 +index cb153ce42..f11b499e1 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.52.0 -From 6f85ab5fb6634424be51cd48c64afe2c2ea33796 Mon Sep 17 00:00:00 2001 +From 88ec91cbb62af9a1f6e832513e7bd0ed3a58f8b1 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -327,7 +327,7 @@ Patchset: cameras 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 9e0763bdc758..0976b267972b 100644 +index 9e0763bdc..0976b2679 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.52.0 -From bae4749173191a62d8642bacf509eccde0885496 Mon Sep 17 00:00:00 2001 +From d43b113bcfde39b2f34cafc35cee360990264e0f Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -370,7 +370,7 @@ Patchset: cameras 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 +index 7807fa329..2d2abb25b 100644 --- a/include/linux/mfd/tps68470.h +++ b/include/linux/mfd/tps68470.h @@ -34,6 +34,7 @@ @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.52.0 -From 723a45f016aaea13b412ce65a97ae4f3a9923117 Mon Sep 17 00:00:00 2001 +From 15375784ea12d3765570207775b8f1a937d34cdb Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -416,7 +416,7 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 06e6291be11b..8f94924ef379 100644 +index 06e6291be..8f94924ef 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -1002,6 +1002,18 @@ config LEDS_TPS6105X @@ -439,7 +439,7 @@ index 06e6291be11b..8f94924ef379 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 9a0333ec1a86..4e1ca8fc9b41 100644 +index 9a0333ec1..4e1ca8fc9 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o @@ -452,7 +452,7 @@ index 9a0333ec1a86..4e1ca8fc9b41 100644 obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c new file mode 100644 -index 000000000000..35aeb5db89c8 +index 000000000..35aeb5db8 --- /dev/null +++ b/drivers/leds/leds-tps68470.c @@ -0,0 +1,185 @@ @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.52.0 -From b3d71cf5004c1b6ff0a388bd1bc098fdb61baca8 Mon Sep 17 00:00:00 2001 +From 1353085e2af88492f9cd453d0550845e0b90fee3 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -660,7 +660,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index 032fbcb981f2..e03a1d8cdcb4 100644 +index 032fbcb98..e03a1d8cd 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c @@ -87,6 +87,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) @@ -676,7 +676,7 @@ index 032fbcb981f2..e03a1d8cdcb4 100644 -- 2.52.0 -From c09eeb95e641f3b06201490b265a453c9ff3ddce Mon Sep 17 00:00:00 2001 +From ef9a9b266336018293d7ab8e38bdaf9508ef0140 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 @@ -693,7 +693,7 @@ Patchset: cameras 4 files changed, 184 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c -index 162b49046990..85cd0c98af03 100644 +index 162b49046..85cd0c98a 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -2,6 +2,7 @@ @@ -940,7 +940,7 @@ index 162b49046990..85cd0c98af03 100644 }, .probe = ov13858_probe, diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c -index d294477f9dd3..46bc6c5b7758 100644 +index d294477f9..46bc6c5b7 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -1396,6 +1396,7 @@ static const struct dev_pm_ops ov5693_pm_ops = { @@ -952,7 +952,7 @@ index d294477f9dd3..46bc6c5b7758 100644 }; MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c -index 4e579352ab2c..ac637207b644 100644 +index 4e579352a..ac637207b 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -60,6 +60,10 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { @@ -967,7 +967,7 @@ index 4e579352ab2c..ac637207b644 100644 IPU_SENSOR_CONFIG("INT3474", 1, 180000000), /* Omnivision OV5670 */ diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 1505fc3ef7a8..20962e8acb26 100644 +index 1505fc3ef..20962e8ac 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -229,6 +229,14 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 61df12b683..f1aa0e96e9 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 8caf1b179f3d3db1c3d4bc43138a2b604eb9a1a3 Mon Sep 17 00:00:00 2001 +From 363fb65941b1a0be6e96ea2c99bcf867591ee636 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 9fa321a95eb3..8914a922be2b 100644 +index 9fa321a95..8914a922b 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -65,7 +65,7 @@ index 9fa321a95eb3..8914a922be2b 100644 -- 2.52.0 -From df07e32f7e0fe91d48c2f8273f356c1de98cdbb0 Mon Sep 17 00:00:00 2001 +From ce356231516a26fcd77d47d9ee5582eeb70dc580 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,7 +80,7 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 8914a922be2b..c43d0a553867 100644 +index 8914a922b..c43d0a553 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 978fc526ed..05e1810768 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From aba054883847d06315ebc5a040f9fdfbe643de03 Mon Sep 17 00:00:00 2001 +From 912222e4789bae13a9bb59ebc0da8dd22b8f9aa4 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 33418dd6768a..f94bbdc1de06 100644 +index 33418dd67..f94bbdc1d 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index aeece6a6d8..0dbcb17cc0 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 4e8ff7f09c09feca6bae9d364c0bd43e479cb03a Mon Sep 17 00:00:00 2001 +From de8b880277239e1670a9206a62b8460254f78ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -27,7 +27,7 @@ Patchset: hid-surface create mode 100644 drivers/hid/hid-surface.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 184a2b2f9347..d2e308b257b5 100644 +index 184a2b2f9..d2e308b25 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1141,6 +1141,14 @@ config HID_SUNPLUS @@ -46,7 +46,7 @@ index 184a2b2f9347..d2e308b257b5 100644 tristate "Synaptics RMI4 device support" select RMI4_CORE diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 3190ece25626..4d2891879548 100644 +index 3190ece25..4d2891879 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -174,6 +174,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ @@ -59,7 +59,7 @@ index 3190ece25626..4d2891879548 100644 diff --git a/drivers/hid/hid-surface.c b/drivers/hid/hid-surface.c new file mode 100644 -index 000000000000..a171ea65672f +index 000000000..a171ea656 --- /dev/null +++ b/drivers/hid/hid-surface.c @@ -0,0 +1,90 @@ @@ -156,7 +156,7 @@ index 000000000000..a171ea65672f -- 2.52.0 -From 77881180b23cb98a470a4864fa0af3785a5ed14a Mon Sep 17 00:00:00 2001 +From 659b9c8cfffb64b9cbea819cb82ce221b8c18ec2 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 @@ -168,7 +168,7 @@ Patchset: hid-surface 1 file changed, 30 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 0eb4f7d1228e..8f2ed29b4f35 100644 +index 0eb4f7d12..8f2ed29b4 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); From 4388608d50caae1581231ce9b65806d9668f744d Mon Sep 17 00:00:00 2001 From: surfacebot Date: Fri, 9 Jan 2026 15:35:03 +0000 Subject: [PATCH 176/236] patches/v6.12: Update to v6.12.64 Generated 14 patches from linux-surface/kernel branch v6.12-surface Base version: v6.12.64 Branch: v6.12-surface Automatically generated patches using git-format-patchsets. --- patches/6.12/0001-secureboot.patch | 14 ++-- patches/6.12/0002-surface3-oemb.patch | 10 +-- patches/6.12/0003-mwifiex.patch | 28 ++++---- patches/6.12/0004-ath10k.patch | 6 +- patches/6.12/0005-ipts.patch | 74 ++++++++++---------- patches/6.12/0006-ithc.patch | 46 ++++++------ patches/6.12/0007-surface-sam-over-hid.patch | 16 ++--- patches/6.12/0008-surface-button.patch | 12 ++-- patches/6.12/0009-surface-typecover.patch | 18 ++--- patches/6.12/0010-surface-shutdown.patch | 10 +-- patches/6.12/0011-surface-gpe.patch | 6 +- patches/6.12/0012-cameras.patch | 66 ++++++++--------- patches/6.12/0013-amd-gpio.patch | 12 ++-- patches/6.12/0014-rtc.patch | 6 +- 14 files changed, 162 insertions(+), 162 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index be2700f1b7..e89ff8262a 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 01edde8580dac0f700507ca50c66ef77881e4d2d Mon Sep 17 00:00:00 2001 +From 63f1542405be6514cdb9504112379c22b748231c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -17,7 +17,7 @@ Patchset: secureboot 1 file changed, 4 insertions(+) diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index b5c79f43359b..a1bbedd989e4 100644 +index b5c79f433..a1bbedd98 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -111,7 +111,11 @@ extra_header_fields: @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.51.0 +2.52.0 -From 1498ad5095e16250353ba89021d731afa695fb2f Mon Sep 17 00:00:00 2001 +From f8e1a06586181686a9ff1df26ac291134759d9cb Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index e88505e945d5..15961654b652 100644 +index e88505e94..15961654b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3085,6 +3085,11 @@ @@ -69,7 +69,7 @@ index e88505e945d5..15961654b652 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 85008ead2ac9..48df5cfafde6 100644 +index 85008ead2..48df5cfaf 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -37,6 +37,7 @@ @@ -108,5 +108,5 @@ index 85008ead2ac9..48df5cfafde6 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index 827d67f433..16a5aa36f0 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 725efa527cfc7d487fa30b61d80c2b9a52c4edb7 Mon Sep 17 00:00:00 2001 +From 5977a8fea25fd09161c5904e33ff90c9f0c36100 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -40,7 +40,7 @@ Patchset: surface3-oemb 3 files changed, 24 insertions(+) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index c15ed7a12784..1ec8edb5aafa 100644 +index c15ed7a12..1ec8edb5a 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { @@ -58,7 +58,7 @@ index c15ed7a12784..1ec8edb5aafa 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 51187b1e0ed2..bfb83ce8d8f8 100644 +index 51187b1e0..bfb83ce8d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -78,7 +78,7 @@ index 51187b1e0ed2..bfb83ce8d8f8 100644 /* * Match for the GPDwin which unfortunately uses somewhat diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0c28..0b930c91bccb 100644 +index e4c3492a0..0b930c91b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { @@ -97,5 +97,5 @@ index e4c3492a0c28..0b930c91bccb 100644 }; -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index 78ced1a910..00b4e1a556 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 1f0efbe2eb539540b68018722c4f85afc14bda95 Mon Sep 17 00:00:00 2001 +From 1106cc5afb2f7db4ca9dc6359952766226a2fe67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -32,7 +32,7 @@ Patchset: mwifiex 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 5f997becdbaa..9a9929424513 100644 +index 5f997becd..9a9929424 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) @@ -58,7 +58,7 @@ index 5f997becdbaa..9a9929424513 100644 mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 +index dd6d21f1d..f46b06f8d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -151,7 +151,7 @@ index dd6d21f1dbfd..f46b06f8d643 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 +index d6ff964ae..5d30ae39d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -4,6 +4,7 @@ @@ -163,9 +163,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.51.0 +2.52.0 -From dabaf45293d28679d9f6d41bd99788d78f1cb24f Mon Sep 17 00:00:00 2001 +From edf9836d0f1d0eea5c98fd1e6de91da2c22472ad Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -187,7 +187,7 @@ Patchset: mwifiex 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 9a9929424513..2273e3029776 100644 +index 9a9929424..2273e3029 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, @@ -212,7 +212,7 @@ index 9a9929424513..2273e3029776 100644 } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 +index f46b06f8d..99b024ecb 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -306,7 +306,7 @@ index f46b06f8d643..99b024ecbade 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 +index 5d30ae39d..c14eb56eb 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -5,6 +5,7 @@ @@ -318,9 +318,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.51.0 +2.52.0 -From f490bcbca816c939c3aa149b11c26081e3387fb2 Mon Sep 17 00:00:00 2001 +From 8f4b822de3c6817607f9c893d541fff7328ea1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index dc0c45756c44..cba0110b17e3 100644 +index 603ff13d9..9209e8e29 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index dc0c45756c44..cba0110b17e3 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -3995,6 +3997,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4009,6 +4011,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index dc0c45756c44..cba0110b17e3 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index bd5e401e5d..4660d02b75 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 71c1ca84a24c0817454d783a3a184b091d19b291 Mon Sep 17 00:00:00 2001 +From 23f0f61a46dc4a43f753a9ed38b27181e6d90510 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index f9b51d98d20b..e04bac901c60 100644 +index f9b51d98d..e04bac901 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -41,6 +41,9 @@ static bool fw_diag_log; @@ -116,5 +116,5 @@ index f9b51d98d20b..e04bac901c60 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index 938ecad68d..51496b1128 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From e3f8caa6000b3a6ba9eca18475e99a69afdbe2f2 Mon Sep 17 00:00:00 2001 +From fef08eee7169b1c1d65252985b201c83c07df382 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index a4f75dc36929..e4a561b257d7 100644 +index a4f75dc36..e4a561b25 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index a4f75dc36929..e4a561b257d7 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index bc0fc584a8e4..51a91ef66cda 100644 +index bc0fc584a..51a91ef66 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index bc0fc584a8e4..51a91ef66cda 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.51.0 +2.52.0 -From 75645d9a045f577b0bbe78444d589bb2d04f1564 Mon Sep 17 00:00:00 2001 +From c0f4c7831822a7c7376dd159758420b1dd99f7a8 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index c799cc67db34..65adfc813ee6 100644 +index c799cc67d..65adfc813 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -40,6 +40,11 @@ @@ -142,9 +142,9 @@ index c799cc67db34..65adfc813ee6 100644 { if (risky_device(dev)) -- -2.51.0 +2.52.0 -From 659fcb72a471a0ab78123458fcf78a27183a8688 Mon Sep 17 00:00:00 2001 +From d924a0bfa4e787757f42c2011c7c8beaae1ee359 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,7 +211,7 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 95a4ede27099..777d4619d06d 100644 +index 95a4ede27..777d4619d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1388,4 +1388,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" @@ -222,7 +222,7 @@ index 95a4ede27099..777d4619d06d 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 27ee02bf6f26..15a67dc834a6 100644 +index 27ee02bf6..15a67dc83 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -170,3 +170,5 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ @@ -233,7 +233,7 @@ index 27ee02bf6f26..15a67dc834a6 100644 +obj-$(CONFIG_HID_IPTS) += ipts/ diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 000000000000..297401bd388d +index 000000000..297401bd3 --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -253,7 +253,7 @@ index 000000000000..297401bd388d + module will be called ipts. diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile new file mode 100644 -index 000000000000..883896f68e6a +index 000000000..883896f68 --- /dev/null +++ b/drivers/hid/ipts/Makefile @@ -0,0 +1,16 @@ @@ -275,7 +275,7 @@ index 000000000000..883896f68e6a +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 000000000000..63a4934bbc5f +index 000000000..63a4934bb --- /dev/null +++ b/drivers/hid/ipts/cmd.c @@ -0,0 +1,61 @@ @@ -342,7 +342,7 @@ index 000000000000..63a4934bbc5f +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 000000000000..2b4079075b64 +index 000000000..2b4079075 --- /dev/null +++ b/drivers/hid/ipts/cmd.h @@ -0,0 +1,60 @@ @@ -408,7 +408,7 @@ index 000000000000..2b4079075b64 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 000000000000..ba33259f1f7c +index 000000000..ba33259f1 --- /dev/null +++ b/drivers/hid/ipts/context.h @@ -0,0 +1,52 @@ @@ -466,7 +466,7 @@ index 000000000000..ba33259f1f7c +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 000000000000..5360842d260b +index 000000000..5360842d2 --- /dev/null +++ b/drivers/hid/ipts/control.c @@ -0,0 +1,486 @@ @@ -958,7 +958,7 @@ index 000000000000..5360842d260b +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 000000000000..26629c5144ed +index 000000000..26629c514 --- /dev/null +++ b/drivers/hid/ipts/control.h @@ -0,0 +1,126 @@ @@ -1090,7 +1090,7 @@ index 000000000000..26629c5144ed +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 000000000000..307438c7c80c +index 000000000..307438c7c --- /dev/null +++ b/drivers/hid/ipts/desc.h @@ -0,0 +1,80 @@ @@ -1176,7 +1176,7 @@ index 000000000000..307438c7c80c +#endif /* IPTS_DESC_H */ diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 000000000000..7b9f54388a9f +index 000000000..7b9f54388 --- /dev/null +++ b/drivers/hid/ipts/eds1.c @@ -0,0 +1,104 @@ @@ -1286,7 +1286,7 @@ index 000000000000..7b9f54388a9f +} diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h new file mode 100644 -index 000000000000..eeeb6575e3e8 +index 000000000..eeeb6575e --- /dev/null +++ b/drivers/hid/ipts/eds1.h @@ -0,0 +1,35 @@ @@ -1327,7 +1327,7 @@ index 000000000000..eeeb6575e3e8 + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c new file mode 100644 -index 000000000000..639940794615 +index 000000000..639940794 --- /dev/null +++ b/drivers/hid/ipts/eds2.c @@ -0,0 +1,145 @@ @@ -1478,7 +1478,7 @@ index 000000000000..639940794615 +} diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h new file mode 100644 -index 000000000000..064e3716907a +index 000000000..064e37169 --- /dev/null +++ b/drivers/hid/ipts/eds2.h @@ -0,0 +1,35 @@ @@ -1519,7 +1519,7 @@ index 000000000000..064e3716907a + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c new file mode 100644 -index 000000000000..e34a1a4f9fa7 +index 000000000..e34a1a4f9 --- /dev/null +++ b/drivers/hid/ipts/hid.c @@ -0,0 +1,225 @@ @@ -1750,7 +1750,7 @@ index 000000000000..e34a1a4f9fa7 +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 000000000000..1ebe77447903 +index 000000000..1ebe77447 --- /dev/null +++ b/drivers/hid/ipts/hid.h @@ -0,0 +1,24 @@ @@ -1780,7 +1780,7 @@ index 000000000000..1ebe77447903 +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 000000000000..fb5b5c13ee3e +index 000000000..fb5b5c13e --- /dev/null +++ b/drivers/hid/ipts/main.c @@ -0,0 +1,126 @@ @@ -1912,7 +1912,7 @@ index 000000000000..fb5b5c13ee3e +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 000000000000..1e0395ceae4a +index 000000000..1e0395cea --- /dev/null +++ b/drivers/hid/ipts/mei.c @@ -0,0 +1,188 @@ @@ -2106,7 +2106,7 @@ index 000000000000..1e0395ceae4a +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 000000000000..973bade6b0fd +index 000000000..973bade6b --- /dev/null +++ b/drivers/hid/ipts/mei.h @@ -0,0 +1,66 @@ @@ -2178,7 +2178,7 @@ index 000000000000..973bade6b0fd +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 000000000000..977724c728c3 +index 000000000..977724c72 --- /dev/null +++ b/drivers/hid/ipts/receiver.c @@ -0,0 +1,251 @@ @@ -2435,7 +2435,7 @@ index 000000000000..977724c728c3 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 000000000000..3de7da62d40c +index 000000000..3de7da62d --- /dev/null +++ b/drivers/hid/ipts/receiver.h @@ -0,0 +1,16 @@ @@ -2457,7 +2457,7 @@ index 000000000000..3de7da62d40c +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 000000000000..cc14653b2a9f +index 000000000..cc14653b2 --- /dev/null +++ b/drivers/hid/ipts/resources.c @@ -0,0 +1,131 @@ @@ -2594,7 +2594,7 @@ index 000000000000..cc14653b2a9f +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 000000000000..2068e13285f0 +index 000000000..2068e1328 --- /dev/null +++ b/drivers/hid/ipts/resources.h @@ -0,0 +1,41 @@ @@ -2641,7 +2641,7 @@ index 000000000000..2068e13285f0 +#endif /* IPTS_RESOURCES_H */ diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h new file mode 100644 -index 000000000000..e8dd98895a7e +index 000000000..e8dd98895 --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -2747,7 +2747,7 @@ index 000000000000..e8dd98895a7e +#endif /* IPTS_SPEC_DATA_H */ diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h new file mode 100644 -index 000000000000..41845f9d9025 +index 000000000..41845f9d9 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h @@ -0,0 +1,290 @@ @@ -3043,7 +3043,7 @@ index 000000000000..41845f9d9025 +#endif /* IPTS_SPEC_DEVICE_H */ diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h new file mode 100644 -index 000000000000..5a58d4a0a610 +index 000000000..5a58d4a0a --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h @@ -0,0 +1,34 @@ @@ -3083,7 +3083,7 @@ index 000000000000..5a58d4a0a610 +#endif /* IPTS_SPEC_HID_H */ diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c new file mode 100644 -index 000000000000..355e92bea26f +index 000000000..355e92bea --- /dev/null +++ b/drivers/hid/ipts/thread.c @@ -0,0 +1,84 @@ @@ -3173,7 +3173,7 @@ index 000000000000..355e92bea26f +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 000000000000..1f966b8b32c4 +index 000000000..1f966b8b3 --- /dev/null +++ b/drivers/hid/ipts/thread.h @@ -0,0 +1,59 @@ @@ -3237,5 +3237,5 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index 1205849c44..e270a96ace 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From e2445c4f69af8d6ea2de2754a6ff084b861ad76d Mon Sep 17 00:00:00 2001 +From fc5fa3bf68958afa207d59d442b42623173fe711 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,7 +10,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 71b3383b7115..8409824b5157 100644 +index 066e4cd6e..7b320d09d 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) @@ -37,9 +37,9 @@ index 71b3383b7115..8409824b5157 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.51.0 +2.52.0 -From a2f09b7f8cce1475141c71586bacc46120146278 Mon Sep 17 00:00:00 2001 +From 3bd90d4e30ceeec7281e1781b35b783109736019 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,7 +86,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 777d4619d06d..d23316df4f5d 100644 +index 777d4619d..d23316df4 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1390,4 +1390,6 @@ source "drivers/hid/surface-hid/Kconfig" @@ -97,7 +97,7 @@ index 777d4619d06d..d23316df4f5d 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 15a67dc834a6..fcbc18ceb521 100644 +index 15a67dc83..fcbc18ceb 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -107,7 +107,7 @@ index 15a67dc834a6..fcbc18ceb521 100644 +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 000000000000..4937ba131297 +index 000000000..4937ba131 --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -119,7 +119,7 @@ index 000000000000..4937ba131297 + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 000000000000..ede713023609 +index 000000000..ede713023 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -137,7 +137,7 @@ index 000000000000..ede713023609 + module will be called ithc. diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c new file mode 100644 -index 000000000000..2d8c6afe9966 +index 000000000..2d8c6afe9 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,149 @@ @@ -292,7 +292,7 @@ index 000000000000..2d8c6afe9966 + diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h new file mode 100644 -index 000000000000..38c53d916bdb +index 000000000..38c53d916 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.h @@ -0,0 +1,7 @@ @@ -305,7 +305,7 @@ index 000000000000..38c53d916bdb + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 000000000000..bf4eab33062b +index 000000000..bf4eab330 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,312 @@ @@ -623,7 +623,7 @@ index 000000000000..bf4eab33062b + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 000000000000..1749a5819b3e +index 000000000..1749a5819 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,47 @@ @@ -676,7 +676,7 @@ index 000000000000..1749a5819b3e + diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c new file mode 100644 -index 000000000000..065646ab499e +index 000000000..065646ab4 --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.c @@ -0,0 +1,207 @@ @@ -889,7 +889,7 @@ index 000000000000..065646ab499e + diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h new file mode 100644 -index 000000000000..599eb912c8c8 +index 000000000..599eb912c --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.h @@ -0,0 +1,32 @@ @@ -927,7 +927,7 @@ index 000000000000..599eb912c8c8 + diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c new file mode 100644 -index 000000000000..8883987fb352 +index 000000000..8883987fb --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.c @@ -0,0 +1,254 @@ @@ -1187,7 +1187,7 @@ index 000000000000..8883987fb352 + diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h new file mode 100644 -index 000000000000..28d692462072 +index 000000000..28d692462 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.h @@ -0,0 +1,8 @@ @@ -1201,7 +1201,7 @@ index 000000000000..28d692462072 + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000000..ac56c253674b +index 000000000..ac56c2536 --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,431 @@ @@ -1638,7 +1638,7 @@ index 000000000000..ac56c253674b + diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c new file mode 100644 -index 000000000000..e2d1690b8cf8 +index 000000000..e2d1690b8 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.c @@ -0,0 +1,607 @@ @@ -2251,7 +2251,7 @@ index 000000000000..e2d1690b8cf8 + diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h new file mode 100644 -index 000000000000..74d882f6b2f0 +index 000000000..74d882f6b --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.h @@ -0,0 +1,39 @@ @@ -2296,7 +2296,7 @@ index 000000000000..74d882f6b2f0 + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 000000000000..c0f13506af20 +index 000000000..c0f13506a --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,154 @@ @@ -2456,7 +2456,7 @@ index 000000000000..c0f13506af20 + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 000000000000..4f541fe533fa +index 000000000..4f541fe53 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,211 @@ @@ -2673,7 +2673,7 @@ index 000000000000..4f541fe533fa + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 000000000000..aec320d4e945 +index 000000000..aec320d4e --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,89 @@ @@ -2767,5 +2767,5 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index 298d95609d..eec5a1323d 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From bed92ec0444735aad7ce2cb42b791c637acaad0b Mon Sep 17 00:00:00 2001 +From 9426284cef0fca02f23a75b33dc8ed39e116e3d1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,7 +55,7 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index f43067f6797e..1761ca30e17a 100644 +index f43067f67..1761ca30e 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, @@ -107,9 +107,9 @@ index f43067f6797e..1761ca30e17a 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.51.0 +2.52.0 -From b9beaed33aca9e6d35802a13fec298bd88654aec Mon Sep 17 00:00:00 2001 +From 1eb7e55a8b1cca487474bc5b6efabfd20f1ff2ae Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -132,7 +132,7 @@ Patchset: surface-sam-over-hid create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index b629e82af97c..68656e8f309e 100644 +index b629e82af..68656e8f3 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH @@ -150,7 +150,7 @@ index b629e82af97c..68656e8f309e 100644 tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 +index 533443309..7efcd0cdb 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o @@ -163,7 +163,7 @@ index 53344330939b..7efcd0cdb532 100644 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 000000000000..68db237734a1 +index 000000000..68db23773 --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c @@ -0,0 +1,136 @@ @@ -304,5 +304,5 @@ index 000000000000..68db237734a1 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index a7231ab92f..d88fcf4157 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From 3161aa7937ea6cf7bc57fec961e74bdd86c2fc6d Mon Sep 17 00:00:00 2001 +From 72ac1d1bb27f99dca1df5b73062e02178e6c132a Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -20,7 +20,7 @@ Patchset: surface-button 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index 5c5d407fe965..4e1bfe90e730 100644 +index 5c5d407fe..4e1bfe90e 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -73,9 +73,9 @@ index 5c5d407fe965..4e1bfe90e730 100644 /* -- -2.51.0 +2.52.0 -From b693acb105f441cae83c53eeffa5f81aa5e80ec9 Mon Sep 17 00:00:00 2001 +From 5c8a82f4b432a636005e19f1991185ed9eb1a8df Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -96,7 +96,7 @@ Patchset: surface-button 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 +index 2755601f9..4240c98ca 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) @@ -145,5 +145,5 @@ index 2755601f979c..4240c98ca226 100644 -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index 2396cf8cdc..de55aee00d 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From 9acb0bf01bdc9975ee5126f6c157519c6b93c212 Mon Sep 17 00:00:00 2001 +From ecb1c88302dacba1813b7e6b482920bd3ba9bbc3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index c322d0c1d965..52ae06afd304 100644 +index c322d0c1d..52ae06afd 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index c322d0c1d965..52ae06afd304 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.51.0 +2.52.0 -From 43b6eeeba1a611d36da3c456be538a8a72a6aaa0 Mon Sep 17 00:00:00 2001 +From 2b744e2b904c695736bde325efe573af78077088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 0e4cb0e668eb..26b5515235cf 100644 +index 0e4cb0e66..26b551523 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -272,9 +272,9 @@ index 0e4cb0e668eb..26b5515235cf 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.51.0 +2.52.0 -From ee3127061887dc88d2b412ad23b4b592045cfee4 Mon Sep 17 00:00:00 2001 +From 05afdfa6c585bdffd6f35c470da129373fee45fb Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 26b5515235cf..37a3e6489091 100644 +index 26b551523..37a3e6489 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -571,5 +571,5 @@ index 26b5515235cf..37a3e6489091 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index 4a7b3fffe6..40dfe38d96 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 58b71fa568056a685b913aa2eef5334707007c52 Mon Sep 17 00:00:00 2001 +From e8e8f9dcf8a6d2981c196c3fdbe193a69b130d56 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 7e9b6e4d4695..93eefd5493e9 100644 +index a00a2ce01..9754d756c 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,7 +37,7 @@ index 7e9b6e4d4695..93eefd5493e9 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 18fa918b4e53..7a7613264e3c 100644 +index 18fa918b4..7a7613264 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6338,3 +6338,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) @@ -81,7 +81,7 @@ index 18fa918b4e53..7a7613264e3c 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 242ee3843e10..96753fb66158 100644 +index 242ee3843..96753fb66 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -482,6 +482,7 @@ struct pci_dev { @@ -93,5 +93,5 @@ index 242ee3843e10..96753fb66158 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index fca2a62feb..bd688f7d2f 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From 6929d34532110795631fe5895a3f54a9281d7250 Mon Sep 17 00:00:00 2001 +From e321c203143de27d3bf7b4feb60ffa8f5db0d3bf Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -12,7 +12,7 @@ Patchset: surface-gpe 1 file changed, 17 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index 62fd4004db31..103fc4468262 100644 +index 62fd4004d..103fc4468 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { @@ -47,5 +47,5 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index 14eea55744..c6c66b77b2 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From 93cecd009a4c3c6bb8bb649c111796098ab54bba Mon Sep 17 00:00:00 2001 +From 908376ffdfb35e8a7fc0b0741168f6981306b7e3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,7 +58,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index ba98763ced7d..6021907ec8ba 100644 +index ba98763ce..6021907ec 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2209,6 +2209,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, @@ -72,9 +72,9 @@ index ba98763ced7d..6021907ec8ba 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.51.0 +2.52.0 -From 1edebcabf4603be9560709d9e667f275510c158c Mon Sep 17 00:00:00 2001 +From b50fa0e9a3d0a92ebe1845f4ae92798a9b602f27 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 65adfc813ee6..3dcabd6c5204 100644 +index 65adfc813..3dcabd6c5 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -45,6 +45,13 @@ @@ -182,9 +182,9 @@ index 65adfc813ee6..3dcabd6c5204 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.51.0 +2.52.0 -From db78c28a8c99bf160b52433e90f3b5ff54ebdd9f Mon Sep 17 00:00:00 2001 +From 04808bcd8b873245f8878c5cb6a243f6a54a1c9b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -201,7 +201,7 @@ Patchset: cameras 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 81ac4c691963..f453c9043042 100644 +index 81ac4c691..f453c9043 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) @@ -219,9 +219,9 @@ index 81ac4c691963..f453c9043042 100644 return 0; -- -2.51.0 +2.52.0 -From 19b281e56886842926c50addf2974a5695ec8ca4 Mon Sep 17 00:00:00 2001 +From 04d6cc0a730b23707e9eccc4a1e269ba027dc74b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -243,7 +243,7 @@ Patchset: cameras 1 file changed, 15 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 9e69ac9cfb92..d6003198aa12 100644 +index 9e69ac9cf..d6003198a 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -81,12 +81,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 @@ -275,9 +275,9 @@ index 9e69ac9cfb92..d6003198aa12 100644 agpio, func, gpio_flags); if (ret) -- -2.51.0 +2.52.0 -From 845d4743b29b9990332528efeb50bdc3ee73d6a7 Mon Sep 17 00:00:00 2001 +From c561d9d986e0ec9972c93505d07754e700d83a62 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -292,7 +292,7 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 3226888d77e9..3bfe45b764f7 100644 +index 3226888d7..3bfe45b76 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) @@ -314,9 +314,9 @@ index 3226888d77e9..3bfe45b764f7 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.51.0 +2.52.0 -From 4b5519ae3d4fc3b303b6b187a5beb63fdda333d6 Mon Sep 17 00:00:00 2001 +From 239cb784959f9c6751edcb8e30246f6e6947a3ac Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -335,7 +335,7 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index ee884a8221fb..4f6bafd900ee 100644 +index ee884a822..4f6bafd90 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) @@ -350,7 +350,7 @@ index ee884a8221fb..4f6bafd900ee 100644 * No reference taken. The reference is held by the device (struct * v4l2_subdev.dev), and async sub-device does not exist independently diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index f19c8adf2c61..923ed1b5ab8b 100644 +index f19c8adf2..923ed1b5a 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) @@ -365,9 +365,9 @@ index f19c8adf2c61..923ed1b5ab8b 100644 if (ret < 0) goto out_cleanup; -- -2.51.0 +2.52.0 -From 552f695429ac278fd55b325571245e111c8c96d7 Mon Sep 17 00:00:00 2001 +From c39a94ea4950d143cae4d8b8683017a89fc3377f Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -383,7 +383,7 @@ Patchset: cameras 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index f453c9043042..b8ad6b413e8b 100644 +index f453c9043..b8ad6b413 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -406,9 +406,9 @@ index f453c9043042..b8ad6b413e8b 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.51.0 +2.52.0 -From 8491189b63c62c1559497df1548863864828b75c Mon Sep 17 00:00:00 2001 +From 738ebac2df91aa10961af97aac1a9f0c339a5a19 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -426,7 +426,7 @@ Patchset: cameras 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 +index 7807fa329..2d2abb25b 100644 --- a/include/linux/mfd/tps68470.h +++ b/include/linux/mfd/tps68470.h @@ -34,6 +34,7 @@ @@ -447,9 +447,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.51.0 +2.52.0 -From 383b9740f8cd9ad0dc1519522975d1140fc2df43 Mon Sep 17 00:00:00 2001 +From cd994d28d4edebc119ba0832c0e03995e53a1c95 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -472,7 +472,7 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index b784bb74a837..f8d8fcfacac2 100644 +index b784bb74a..f8d8fcfac 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -941,6 +941,18 @@ config LEDS_TPS6105X @@ -495,7 +495,7 @@ index b784bb74a837..f8d8fcfacac2 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 18afbb5a23ee..a1d16c0af82d 100644 +index 18afbb5a2..a1d16c0af 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o @@ -508,7 +508,7 @@ index 18afbb5a23ee..a1d16c0af82d 100644 obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c new file mode 100644 -index 000000000000..35aeb5db89c8 +index 000000000..35aeb5db8 --- /dev/null +++ b/drivers/leds/leds-tps68470.c @@ -0,0 +1,185 @@ @@ -698,9 +698,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.51.0 +2.52.0 -From 205b138b1b045a9bd8fa8aeadb9aeec862c606a8 Mon Sep 17 00:00:00 2001 +From 1c3470f95886ee86781fa164a70ecc5f0b51dfa2 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -716,7 +716,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..0094cfda57ea 100644 +index c626ed845..0094cfda5 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c @@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719) @@ -730,5 +730,5 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index 385bd426e6..9b8aff6359 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From 5281dfaba9efa2cd29a0ad637fe57658ea80ecca Mon Sep 17 00:00:00 2001 +From 4f72a8fba6496c49f0205e21772c7781f5f2e6d0 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 63adda8a143f..00914222a705 100644 +index 63adda8a1..00914222a 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -63,9 +63,9 @@ index 63adda8a143f..00914222a705 100644 mp_config_acpi_legacy_irqs(); -- -2.51.0 +2.52.0 -From 660e2e2e671331aa89b513c8a53de6440dc6ef59 Mon Sep 17 00:00:00 2001 +From 796bdd93f2c2a1026d70100f304caef38662f361 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,7 +80,7 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 00914222a705..2b35bb58b0e2 100644 +index 00914222a..2b35bb58b 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1177,12 +1177,19 @@ static void __init mp_config_acpi_legacy_irqs(void) @@ -105,5 +105,5 @@ index 00914222a705..2b35bb58b0e2 100644 }; -- -2.51.0 +2.52.0 diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index 8b820d6d9d..b3a37af02d 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From 0033720ba60019e428c982347a491823d52f8d51 Mon Sep 17 00:00:00 2001 +From e2c9f4a3dfa5587ce98a77222db6b960c427d3fe Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index b75ceaab716e..3dfcfd32d574 100644 +index b75ceaab7..3dfcfd32d 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, @@ -106,5 +106,5 @@ index b75ceaab716e..3dfcfd32d574 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.51.0 +2.52.0 From 8d92d29d5dc71c9a7332be9643038eb906bef873 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 11 Jan 2026 00:17:07 +0100 Subject: [PATCH 177/236] Update Arch kernel to v6.18.4 --- pkg/arch/kernel/PKGBUILD | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 9ac7be6209..52296f2828 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,8 +3,8 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.18.3.arch1 -pkgrel=2 +pkgver=6.18.4.arch1 +pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -64,26 +64,26 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('b5af77758935f761ee42b9aa407809bb1dc5fd15ee379a73f66e14c7dca75300' +sha256sums=('32acb39c02fdca2ff64fb2e03ce72f8988966ed736f0429270b6fc305ec252f5' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - 'ace28c38ca03c0fdc66b265e3ef2b7a0153740c0eb815ff6cdfc5d2df3f12580' - '38bf267d08ea74dc0a0762c92eb6512e7c2a786af4eab1a3856dd03ce6a35246' - '5b994cc6deeb2205f97b600721363d006ccfaf9453b3d15c4bec4c10b53c7ff6' - 'ef472c1e49e46744ab588d591b25cfe6b2d465e67aba227da9db91931fec969a' - '6a6e359e461bc888752fa60251331a97b6a1a99944d316d65cb2ac7148415794' - 'b843d8f38827a34e73ee602469a0eb9d43e29d3e5061aa11b3bc22ff384d2c8c' - '282a9de0adfd5298274c62e865983932e18cd759318dcad60108ad2928029d9e' - 'c80b11ea2c15ed69abb4befad0c8cba096a3f0a46f70f40a6242c812aaa25b31' - 'f7f0f9306350409efdcd5a126f70286aa1a4b261bae869273b40584cc2568c65' - '17f01763f4b44703d2a788f2756bac91ce7d872db66372223ef77302f032927b' - '0b7030f27ca965acc944c1f924f1a89e91b25a344bdbc9f6a6945bc8ee4ad197' - 'f613337f549cdcbf57444f0ab67cfb2d12eb84a003bcec1be887f6508eac9953' - '86a89eb63f8783d395a44fa304cde866802ec8072d1ea2e2eafd0f7f1e9e7dbb' - 'e064ea18c367a55e439081551792a9609a50f4fcc7732bb287f13cb62bb07b69' - 'f1ba0a216c6622d79e8618c37a4f298d06053edb9b829f235472feeee7bbcf24' - '2dbcd9e2115346415cedc0e85fa729d1ac5ef2e47ab8d5d04c6c5dfb482287fc') + '19e31661fceddb0a19b3b7fa8b4ef22debabe2d9c710dd934da268d89e3c887a' + 'cd75e205c88a46492973b62cffd6a665899acce649af1676517b8a47fc89d61d' + 'a2bef750ccdcfced8321385c7605354d09a2372a169682458f41f3de837853b7' + '6d57f5f0a112fb942860e5a6ba28cb393cab65f07814a472bbbfb6d3eca325a8' + 'adb66156f0c76d8422ab109e84659a31c87b73f827d582e02db7e37a23705dbf' + 'ac410af463ceca41723f6ad6050077a15369ad724caf67c6bab71959588d8016' + '2d79095488dbb508af14e6d16bdbf89bf4796034e83a3998a3c02a38cc7b43c4' + 'bb0e278a731e9e17a65ec67946ca20a9d0b4cbc4b70c08c3f78c1e217e93310c' + '80b472c2c2dadbd3aef880e3a74f4dacbda4f60bf7f3b467d881a721b6eac18d' + '5850c7bc3d250cab6f5cbbada73826899315c044568a74bf20a6ef68b988c9ea' + '06983080488b968a9530613e1b9cc6d9a37c996d2e1fed538ecbae207b1bf2c1' + '18ada8936393aaecd48a09cbfdf554423cc9e63419a669347b521816289eded9' + 'e0fe808db02d187a16d9973672c75a841e71c32bef2e3526c5ceabd9167fdfa1' + '8f676321012dd38afd100eb20e1c6abb4fd3e1f1467ff93204e72e8fa71aaf11' + '969182388990fc7eddf69bd94494ca80b955140595063e01b2ab42b26c43fde7' + '38e372f4096e2758a3db6f1ca942abcc7062b5abc3e9fbaad7abb706edc9b254') export KBUILD_BUILD_HOST=archlinux From 72927987bd153c62d883a118a3fa353e51a9e213 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 11 Jan 2026 00:18:35 +0100 Subject: [PATCH 178/236] Update Debian kernel to v6.18.4 --- pkg/debian/kernel/version.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 390a134c93..8acdbccc7c 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.18.3" -KERNEL_REVISION="2" +KERNEL_VERSION="6.18.4" +KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 9995c2fb2bb922dd846edf0a9ddd6478d55d42c1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 11 Jan 2026 00:20:36 +0100 Subject: [PATCH 179/236] Update Fedora kernel to v6.18.4 --- pkg/fedora/kernel-surface/build-linux-surface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 42f7deb487..6c4566ca33 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,13 +19,13 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.17.13-0" +PACKAGE_TAG = "kernel-6.18.4-0" ## ## The release number of the modified kernel package. ## e.g. 300 for kernel-6.3.1-300.fc38.foo ## -PACKAGE_RELEASE = "4" +PACKAGE_RELEASE = "1" ## ## Build options for configuring which parts of the kernel package are enabled. From c9e9329d319a7968bdfd3db6b909785a10432c8b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 12 Jan 2026 10:27:43 +0100 Subject: [PATCH 180/236] .github/workflows/sync-kernel-upstream: Fix missing checkout --- .github/workflows/sync-kernel-upstream.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/sync-kernel-upstream.yml b/.github/workflows/sync-kernel-upstream.yml index d322f27a18..ebfba75ddf 100644 --- a/.github/workflows/sync-kernel-upstream.yml +++ b/.github/workflows/sync-kernel-upstream.yml @@ -31,6 +31,11 @@ jobs: jq -r 'sort_by(.createdAt) | reverse | .[1:] | .[].id' | \ xargs -I {} gh cache delete {} --repo ${{ github.repository }} || true + - name: Checkout linux-surface repo + uses: actions/checkout@v6 + with: + token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} + - name: Checkout kernel repository uses: actions/checkout@v6 with: From 6aa4e330af4aee9d834920da4c0ebb86e1e2dea5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 12 Jan 2026 13:59:46 +0100 Subject: [PATCH 181/236] .github/workflows/sync-kernel-upstream: Fix checkout parameters --- .github/workflows/sync-kernel-upstream.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/sync-kernel-upstream.yml b/.github/workflows/sync-kernel-upstream.yml index ebfba75ddf..4a5e1ab9fc 100644 --- a/.github/workflows/sync-kernel-upstream.yml +++ b/.github/workflows/sync-kernel-upstream.yml @@ -34,6 +34,8 @@ jobs: - name: Checkout linux-surface repo uses: actions/checkout@v6 with: + repository: linux-surface/linux-surface + path: linux-surface token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} - name: Checkout kernel repository From ea76206c5531fcdd22ad619ac8df3186974c1c43 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Mon, 12 Jan 2026 14:37:42 +0000 Subject: [PATCH 182/236] patches/v6.18: Update to v6.18.5 Generated 16 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.5 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 4 ++-- patches/6.18/0002-surface3.patch | 4 ++-- patches/6.18/0003-mwifiex.patch | 6 +++--- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 6 +++--- patches/6.18/0006-ithc.patch | 4 ++-- patches/6.18/0007-surface-sam.patch | 4 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 4 ++-- patches/6.18/0009-surface-button.patch | 4 ++-- patches/6.18/0010-surface-typecover.patch | 6 +++--- patches/6.18/0011-surface-shutdown.patch | 4 ++-- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 20 ++++++++++---------- patches/6.18/0014-amd-gpio.patch | 4 ++-- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 4 ++-- 16 files changed, 40 insertions(+), 40 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 8d2f4e545a..32696ea5db 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From b0e0398f4f468ece3c20371fe1c7d12d5b168140 Mon Sep 17 00:00:00 2001 +From 1bbb1f037b8827971c5a6ef902e0b46a560bb49f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2..25848f886 100644 -- 2.52.0 -From 9b9d346c25feaab026a21b9e430d42c9dbc70215 Mon Sep 17 00:00:00 2001 +From d12ba6f313df27a23dfbedd33eb27a66e54433d3 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index 79ba196eee..7fce5c4555 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 87c2e72e7547137bd0a22818208c26640526c59f Mon Sep 17 00:00:00 2001 +From 41fd825cc8e72c3aeb75477c51113e7e6922a47b Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0..0b930c91b 100644 -- 2.52.0 -From 2b85458ab9beb7f81618c5a71e4446be86850d89 Mon Sep 17 00:00:00 2001 +From 5377c5f58271e97b209e0e0cbdc5130fae0181c4 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index b6f806bccb..107354d293 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From a10a3d9a31c5fdd5748f796dd02787bbdcc219ac Mon Sep 17 00:00:00 2001 +From 30529332e1f6cc038e52456946a4d8b20864bc7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From 3f5365b05fcaa1e9a01ddbd1b4fbfb3cf13ed6b8 Mon Sep 17 00:00:00 2001 +From 87a78acab5967185d744bc20b50b817347ace0c4 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From ac70d7580b1d368d2a2174ad7c9165fdd2cf37de Mon Sep 17 00:00:00 2001 +From 5688a8233080b57b7d7f2fe5ce8d9abc04f4c9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index 5bcd7f13f5..bcbec32145 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From b7fa0d87576307a4525d8f047e8efacab66df2ca Mon Sep 17 00:00:00 2001 +From 7f620f005272c98c82d2e1ea77a5442e99977b97 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 3d659c8d56..0fe0eacb32 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 22c4f1b753aa6f381bc367bf16f4bed0b8187386 Mon Sep 17 00:00:00 2001 +From 3a23613571db186f35b71c30798c57cb41bd592d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 73cad914b..807e352af 100644 -- 2.52.0 -From 34ac5358779ab71f9ee1c0d831842473a0579231 Mon Sep 17 00:00:00 2001 +From 9ea1d8c6cb18eb013c94a91eb10984693a0e5d23 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e236c7ec2..9e31a5fe1 100644 -- 2.52.0 -From 7a787a4d3d3173955c241673f365333a71748949 Mon Sep 17 00:00:00 2001 +From af0f6a541e284ab2f46077facc08fbb8bfb40fd2 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index 964f830dd6..a580894fa2 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From ccbd80a1526b82e7f76cc1808775ed952fce90f1 Mon Sep 17 00:00:00 2001 +From 7c8c6138ea744eb959eeea1f698b0742696a1a57 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9..c78806d35 100644 -- 2.52.0 -From 3e9189b92d72fc0859c39687794f55b36e270c6c Mon Sep 17 00:00:00 2001 +From 1cf2aa6e51cc654c0fb29b8ce3619ae55d1a0d99 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index c598f19f20..17119ef084 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 341b34d9fbf0bf7351f2dc481a2acf5e5076829b Mon Sep 17 00:00:00 2001 +From c31d2f6813605ca6957ece3a190ff8c5e6a38949 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000..f6c17c4e9 -- 2.52.0 -From 2971c838857dcd170848a1f655b06a26f2b3541f Mon Sep 17 00:00:00 2001 +From e6a3cef76cf1b9bfbf517d38fbb4078d9594cfe7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index dedf78a483..1097c38582 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 7ecd3735e92ad10f072ea5755e30aa70f1de04fb Mon Sep 17 00:00:00 2001 +From d3664722e4011fff0ad8c6587c57295bd05643f8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a2..070c36637 100644 -- 2.52.0 -From 497dd96a69fac182bc2f1dc110ec32789839deee Mon Sep 17 00:00:00 2001 +From 543bca549766be688af3e8cd8739059e4b7d66d1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 76969c2e1d..56b6750b7a 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 66db0bcac62218421b6ed1662f2688933dab48f4 Mon Sep 17 00:00:00 2001 +From 4a861d096e575cb4276772501b4ba31b1be2c068 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c..43b5d5638 100644 -- 2.52.0 -From b051f52f5fe5748b4877f73b81f91d38a5033c1c Mon Sep 17 00:00:00 2001 +From 06f3f9d53e6776f02c4d32d739ae89c82b24431c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index 90eb86c91a..88f7749e07 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 8e7a306e02f3631bb15804dcacc372dc4ee28406 Mon Sep 17 00:00:00 2001 +From 259aa8c7eb475ec80810a57f052226a33cb5141d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 47f589c41..6b00aec67 100644 -- 2.52.0 -From 8b8670b3421cb324331011f714df157ec658844a Mon Sep 17 00:00:00 2001 +From afd6c78a0e6bca37e5df34c630b7b26665da1d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 179dc316b..7d644e1c4 100644 -- 2.52.0 -From 3bb9c674792795fe54da7901bfc638daffdf9446 Mon Sep 17 00:00:00 2001 +From a76c1b739d57247de62b3cfd28f0524dac280292 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index f06466020d..6c76130378 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From bab8498e8af2474d85f8a6c3f8396dbf9dbf8d2e Mon Sep 17 00:00:00 2001 +From 7a544468a6af1e5660f7ab6151e3ad676ebfec74 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index bf97d49c2..90eead93d 100644 -- 2.52.0 -From 1afc88118fa7014d5d6ef99c48d14468393ad422 Mon Sep 17 00:00:00 2001 +From d432ea18a56ef2f8ddcc29bbe8b9c91014138e9c Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index e7dd74892a..85820650de 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From cec5167e48fe6afb38dd75cf6f0f700566313267 Mon Sep 17 00:00:00 2001 +From dba267593ba95bf9c1597a856e7b4444857597ab Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index 6fe0ce61a8..e4962fd1f6 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From 1b27298c89877c41dbcc314443d75fe910e22853 Mon Sep 17 00:00:00 2001 +From e75f2d73aa53f48967aab634634395a2a2613a62 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2..a6bad2679 100644 -- 2.52.0 -From 877aeb2d25ada1c118875cfdb3729693f35c5ff4 Mon Sep 17 00:00:00 2001 +From 495a72e2b98c75b52ba61d37b59bfa9831a5022b Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 9e31a5fe1..bdd32551c 100644 -- 2.52.0 -From 3234b69803a65f71309184b4c041e35f3d23eaf9 Mon Sep 17 00:00:00 2001 +From cd0bb895ba436a10646eb72ed15f981e693ef09a Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 013340569..9e0763bdc 100644 -- 2.52.0 -From a3471b5fa576339b79789e4894511d8577034ae8 Mon Sep 17 00:00:00 2001 +From 75a3d5630b9a965cb48ecf09d0b0d9be9c3e2100 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0..28b192c9a 100644 -- 2.52.0 -From f1cd3e354b93cf64d376d05bbd8eaf6dc5ba599c Mon Sep 17 00:00:00 2001 +From a2e0668c55f529d0abe95cf822bd4b86222f81bb Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42..f11b499e1 100644 -- 2.52.0 -From 88ec91cbb62af9a1f6e832513e7bd0ed3a58f8b1 Mon Sep 17 00:00:00 2001 +From 98bb0310011338a2ab70d7536952ab1caf35e6a4 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc..0976b2679 100644 -- 2.52.0 -From d43b113bcfde39b2f34cafc35cee360990264e0f Mon Sep 17 00:00:00 2001 +From 534f5cb94af7f067f24c0a204e98b7d9a513cd45 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From 15375784ea12d3765570207775b8f1a937d34cdb Mon Sep 17 00:00:00 2001 +From 2094bfb94b193ec8f975f0d602aeef444d8880da Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From 1353085e2af88492f9cd453d0550845e0b90fee3 Mon Sep 17 00:00:00 2001 +From eba864a5f58712f7a6ce3555484092485637938a Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb98..e03a1d8cd 100644 -- 2.52.0 -From ef9a9b266336018293d7ab8e38bdaf9508ef0140 Mon Sep 17 00:00:00 2001 +From f25ebe5b31578d2a4d4e66c3817ce4e0c9f412b8 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index f1aa0e96e9..b2e99a4020 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 363fb65941b1a0be6e96ea2c99bcf867591ee636 Mon Sep 17 00:00:00 2001 +From db3ec9540d493a473491fca1391969ad00212db8 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95..8914a922b 100644 -- 2.52.0 -From ce356231516a26fcd77d47d9ee5582eeb70dc580 Mon Sep 17 00:00:00 2001 +From f2dcd89f3807295c28eb8248140735dca8b4a9d5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 05e1810768..0245c8b870 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 912222e4789bae13a9bb59ebc0da8dd22b8f9aa4 Mon Sep 17 00:00:00 2001 +From 0dfdb22b626f288d56d9a41530ccdfb84a8baa47 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index 0dbcb17cc0..8adabc931b 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From de8b880277239e1670a9206a62b8460254f78ef5 Mon Sep 17 00:00:00 2001 +From ddec4ff683bbbb1e92e4fa30adcefe93b38c2cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000..a171ea656 -- 2.52.0 -From 659b9c8cfffb64b9cbea819cb82ce221b8c18ec2 Mon Sep 17 00:00:00 2001 +From 16174508fdd5cdfaebb39bc5c1747c09679b7a70 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 From 5265ba07c1988ab05d99bbab581d90c693a8eab9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 13 Jan 2026 22:34:29 +0100 Subject: [PATCH 183/236] Update Fedora kernels to v6.18.5 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 6c4566ca33..b1b74d9ce2 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.18.4-0" +PACKAGE_TAG = "kernel-6.18.5-0" ## ## The release number of the modified kernel package. From 3575708927264fad692dc42bc33eba21c40795ac Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 13 Jan 2026 22:35:13 +0100 Subject: [PATCH 184/236] Update Debian kernel to v6.18.5 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 8acdbccc7c..968dff8ed4 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.18.4" +KERNEL_VERSION="6.18.5" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 928912d71bd6bcc2f1d2502cb4205abb1bfed8f1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 13 Jan 2026 22:35:59 +0100 Subject: [PATCH 185/236] Update Arch kernel to v6.18.5 --- pkg/arch/kernel/PKGBUILD | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 52296f2828..3bdb34f182 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.18.4.arch1 +pkgver=6.18.5.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -64,26 +64,26 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('32acb39c02fdca2ff64fb2e03ce72f8988966ed736f0429270b6fc305ec252f5' +sha256sums=('b5d871948897d5e498d057e1536f3777c00f441e668b9a7febeb717435a0941b' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '19e31661fceddb0a19b3b7fa8b4ef22debabe2d9c710dd934da268d89e3c887a' - 'cd75e205c88a46492973b62cffd6a665899acce649af1676517b8a47fc89d61d' - 'a2bef750ccdcfced8321385c7605354d09a2372a169682458f41f3de837853b7' - '6d57f5f0a112fb942860e5a6ba28cb393cab65f07814a472bbbfb6d3eca325a8' - 'adb66156f0c76d8422ab109e84659a31c87b73f827d582e02db7e37a23705dbf' - 'ac410af463ceca41723f6ad6050077a15369ad724caf67c6bab71959588d8016' - '2d79095488dbb508af14e6d16bdbf89bf4796034e83a3998a3c02a38cc7b43c4' - 'bb0e278a731e9e17a65ec67946ca20a9d0b4cbc4b70c08c3f78c1e217e93310c' - '80b472c2c2dadbd3aef880e3a74f4dacbda4f60bf7f3b467d881a721b6eac18d' - '5850c7bc3d250cab6f5cbbada73826899315c044568a74bf20a6ef68b988c9ea' - '06983080488b968a9530613e1b9cc6d9a37c996d2e1fed538ecbae207b1bf2c1' - '18ada8936393aaecd48a09cbfdf554423cc9e63419a669347b521816289eded9' - 'e0fe808db02d187a16d9973672c75a841e71c32bef2e3526c5ceabd9167fdfa1' - '8f676321012dd38afd100eb20e1c6abb4fd3e1f1467ff93204e72e8fa71aaf11' - '969182388990fc7eddf69bd94494ca80b955140595063e01b2ab42b26c43fde7' - '38e372f4096e2758a3db6f1ca942abcc7062b5abc3e9fbaad7abb706edc9b254') + '5ff34a1fb3f64692bc37968e8574fe87cc67febed0ca0dc370b56185214c91fc' + '5ee83652d8475a092c3c20cdaa3f4389da847b2b4a016e3d8fbd461d09ec6edb' + 'add901e1529eb75b9e1ba33eb01a9c8939db79fb9127aaa8302b8699cfb529bb' + '2a51a027d6d6da802f3eecaca93c79adb83a3abe3e03b26737070e50aff15e96' + '8511e16a3c492bee1d3dcc2dee23d3150ece3dee4e44d42803a5358eac7bf151' + '76a55691ccb7739b7ff7d2db8e7853953abdec4f20d6feb08641a3ca0c3b0228' + 'f721b66d0a75129202165a27ef682946964d8e3835ae9a69a0fb43909d14166b' + '5b81488ae1a437c2e31032331c8e7700cdfe58c3bd2cd559c039c2860caeab5c' + '13149b4239df2d38a1449e1cc608548f5f449bc9cad806acf3eaa39ce539b6b6' + '0245dbf371829f251fbe1d07f519c22d5198bb72b8c00ba76bbbe11f154a94ee' + 'dd6a53d3c65a5a24078c880bfa010b074b9de27983e08290664b1f50908e86dd' + '9feef378c2838706b41ae5f8b48f0aa4e219532a02be236964b007636e1abb67' + '192ed7cb4d0efee35e7a638b6e650fa6ac99e594fc34f475fddac86ddeb040ed' + 'd3f6df3574ba20915d1b55bf9bb48c5f445a5d9bd291fd3eac30714cd4df2b8a' + 'ad9fca07451fe81f058c89d7f1dc8524dd02e5282a0ddc243f8a35c0a57c4df9' + '83dea9c314f928a332a64b6fd004af25d295f8ae1041d4218cb0130a2e35a11c') export KBUILD_BUILD_HOST=archlinux From 6318fd9efa8364f46b58cf589b18f5b9775b015f Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Thu, 15 Jan 2026 18:40:55 -0500 Subject: [PATCH 186/236] Backport Ice Lake throttling fix API Backports https://lore.kernel.org/linux-pm/CAJZ5v0jA6DiP=FoiWo2fs3sU7Do3ykgURoV+dzKE68NL9T5YFQ@mail.gmail.com/ from 6.20 --- patches/6.18/0017-powercap.patch | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 patches/6.18/0017-powercap.patch diff --git a/patches/6.18/0017-powercap.patch b/patches/6.18/0017-powercap.patch new file mode 100644 index 0000000000..8b79b0f058 --- /dev/null +++ b/patches/6.18/0017-powercap.patch @@ -0,0 +1,29 @@ +From a1c886a619ddf7245f2a5cc51404baacb92c29c6 Mon Sep 17 00:00:00 2001 +From: Daniel Tang +Date: Wed, 14 Jan 2026 20:31:38 -0500 +Subject: [PATCH] powercap: intel_rapl: Add PL4 support for Ice Lake + +Microsoft Surface Pro 7 firmware throttles the processor upon +boot/resume. Userspace needs to be able to restore the correct value. + +Link: https://github.com/linux-surface/linux-surface/issues/706 +Signed-off-by: Daniel Tang +--- + drivers/powercap/intel_rapl_msr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c +index 9a7e150b3536..a2bc0a9c1e10 100644 +--- a/drivers/powercap/intel_rapl_msr.c ++++ b/drivers/powercap/intel_rapl_msr.c +@@ -162,6 +162,7 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra) + + /* List of verified CPUs. */ + static const struct x86_cpu_id pl4_support_ids[] = { ++ X86_MATCH_VFM(INTEL_ICELAKE_L, NULL), + X86_MATCH_VFM(INTEL_TIGERLAKE_L, NULL), + X86_MATCH_VFM(INTEL_ALDERLAKE, NULL), + X86_MATCH_VFM(INTEL_ALDERLAKE_L, NULL), +-- +2.51.0 + From 7479cd31c190706f9ed6f49389c80020c77f318a Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sun, 18 Jan 2026 09:12:41 +0000 Subject: [PATCH 187/236] patches/v6.18: Update to v6.18.6 Generated 16 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.6 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 4 ++-- patches/6.18/0002-surface3.patch | 4 ++-- patches/6.18/0003-mwifiex.patch | 6 +++--- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 10 +++++----- patches/6.18/0006-ithc.patch | 4 ++-- patches/6.18/0007-surface-sam.patch | 4 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 4 ++-- patches/6.18/0009-surface-button.patch | 4 ++-- patches/6.18/0010-surface-typecover.patch | 6 +++--- patches/6.18/0011-surface-shutdown.patch | 4 ++-- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 20 ++++++++++---------- patches/6.18/0014-amd-gpio.patch | 4 ++-- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 4 ++-- 16 files changed, 42 insertions(+), 42 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 32696ea5db..4a6710ea07 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 1bbb1f037b8827971c5a6ef902e0b46a560bb49f Mon Sep 17 00:00:00 2001 +From e3344768c391d3e4980996f6e02330fe797ba927 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2..25848f886 100644 -- 2.52.0 -From d12ba6f313df27a23dfbedd33eb27a66e54433d3 Mon Sep 17 00:00:00 2001 +From cbfac26900958a27f0ef1ee7c0f29b331dbceee0 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index 7fce5c4555..8bddebbfc7 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 41fd825cc8e72c3aeb75477c51113e7e6922a47b Mon Sep 17 00:00:00 2001 +From 0e12e6b52c20b3b156629ad558f790e1103634f4 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0..0b930c91b 100644 -- 2.52.0 -From 5377c5f58271e97b209e0e0cbdc5130fae0181c4 Mon Sep 17 00:00:00 2001 +From 3d036e8ef8991ae8d8f41448ad1bf69121b95fb4 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 107354d293..9a9cb1a732 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 30529332e1f6cc038e52456946a4d8b20864bc7d Mon Sep 17 00:00:00 2001 +From ea0e49ee498b64c010e74611aaf0b178d8016aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From 87a78acab5967185d744bc20b50b817347ace0c4 Mon Sep 17 00:00:00 2001 +From cdc60849a4e5f83427268d6daa651b4ee5059621 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 5688a8233080b57b7d7f2fe5ce8d9abc04f4c9da Mon Sep 17 00:00:00 2001 +From 6e8dfacc75693497fca42bc6a2e83a709c28c793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index bcbec32145..2edf05b8a2 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 7f620f005272c98c82d2e1ea77a5442e99977b97 Mon Sep 17 00:00:00 2001 +From 321436678300fdb5cccf60f692aadc8b9b0d02b5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 0fe0eacb32..1ea21e8f47 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 3a23613571db186f35b71c30798c57cb41bd592d Mon Sep 17 00:00:00 2001 +From 7d4b029eae825c38b06628dca4dfb094abfdf466 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index a4f75dc36..e4a561b25 100644 +index fa30899a5..a1864dcb7 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index a4f75dc36..e4a561b25 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 73cad914b..807e352af 100644 +index 2a6e56955..c19dfba54 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -37,7 +37,7 @@ index 73cad914b..807e352af 100644 -- 2.52.0 -From 9ea1d8c6cb18eb013c94a91eb10984693a0e5d23 Mon Sep 17 00:00:00 2001 +From 89781c65888bc9b3d86c746e81368f88cac13ac4 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e236c7ec2..9e31a5fe1 100644 -- 2.52.0 -From af0f6a541e284ab2f46077facc08fbb8bfb40fd2 Mon Sep 17 00:00:00 2001 +From 6e0741b765c1db5a62bb07c9b8701fa8d8605f5a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index a580894fa2..cfda0c38ef 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From 7c8c6138ea744eb959eeea1f698b0742696a1a57 Mon Sep 17 00:00:00 2001 +From 7e9b8475a04d1ce2957cdd8ea777158d21b0c480 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9..c78806d35 100644 -- 2.52.0 -From 1cf2aa6e51cc654c0fb29b8ce3619ae55d1a0d99 Mon Sep 17 00:00:00 2001 +From d0648197b84aa176988d669969b60b8809d32e7e Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index 17119ef084..a4470373cf 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From c31d2f6813605ca6957ece3a190ff8c5e6a38949 Mon Sep 17 00:00:00 2001 +From 136fda6da11f8108d830afad579148236ba06dfd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000..f6c17c4e9 -- 2.52.0 -From e6a3cef76cf1b9bfbf517d38fbb4078d9594cfe7 Mon Sep 17 00:00:00 2001 +From c12f4b52dffee6c0c45ac8034155a2a942791bfa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 1097c38582..4c2abf4ef8 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From d3664722e4011fff0ad8c6587c57295bd05643f8 Mon Sep 17 00:00:00 2001 +From df4c86a5039ca68258a22f32ead2d35d55312ecf Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a2..070c36637 100644 -- 2.52.0 -From 543bca549766be688af3e8cd8739059e4b7d66d1 Mon Sep 17 00:00:00 2001 +From 3821285cceabe2ca3ae176a2702a9183bd2967ca Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 56b6750b7a..4746a6dc66 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 4a861d096e575cb4276772501b4ba31b1be2c068 Mon Sep 17 00:00:00 2001 +From 358f7910e7d6b687a42b29bb7a9c33726604ea61 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c..43b5d5638 100644 -- 2.52.0 -From 06f3f9d53e6776f02c4d32d739ae89c82b24431c Mon Sep 17 00:00:00 2001 +From 91459003685804cdf68739d5f5104609ca39ccc6 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index 88f7749e07..eaee1254f6 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 259aa8c7eb475ec80810a57f052226a33cb5141d Mon Sep 17 00:00:00 2001 +From 7056ab9026176ab860df770eed65cbe08573ee55 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 47f589c41..6b00aec67 100644 -- 2.52.0 -From afd6c78a0e6bca37e5df34c630b7b26665da1d87 Mon Sep 17 00:00:00 2001 +From 67e9cc13be702451b2d83c9542c7fd5ab8efcf24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 179dc316b..7d644e1c4 100644 -- 2.52.0 -From a76c1b739d57247de62b3cfd28f0524dac280292 Mon Sep 17 00:00:00 2001 +From defac4657f8e5d3f44d8ebe3d02d9e8b39601e55 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index 6c76130378..bdb6d71f6f 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 7a544468a6af1e5660f7ab6151e3ad676ebfec74 Mon Sep 17 00:00:00 2001 +From 443f7de4ee944e938ca0c90b89152bb1fce8aa31 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index bf97d49c2..90eead93d 100644 -- 2.52.0 -From d432ea18a56ef2f8ddcc29bbe8b9c91014138e9c Mon Sep 17 00:00:00 2001 +From 503713abb5374b1fc12c26972e18de70bf00250c Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index 85820650de..b113847f96 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From dba267593ba95bf9c1597a856e7b4444857597ab Mon Sep 17 00:00:00 2001 +From 4df121228542c37c2771e470147ba6d3f88ee6cc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index e4962fd1f6..aaa9113e8a 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From e75f2d73aa53f48967aab634634395a2a2613a62 Mon Sep 17 00:00:00 2001 +From c8a93f5e492ef439cc44383b2000a02802f2638e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2..a6bad2679 100644 -- 2.52.0 -From 495a72e2b98c75b52ba61d37b59bfa9831a5022b Mon Sep 17 00:00:00 2001 +From 6c66043178d66f7b67a080cba9759be06cde03a8 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 9e31a5fe1..bdd32551c 100644 -- 2.52.0 -From cd0bb895ba436a10646eb72ed15f981e693ef09a Mon Sep 17 00:00:00 2001 +From c62706701d19ecb98060af9204dd0fb254dca2f5 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 013340569..9e0763bdc 100644 -- 2.52.0 -From 75a3d5630b9a965cb48ecf09d0b0d9be9c3e2100 Mon Sep 17 00:00:00 2001 +From b4af7c93a1a456f669cdca4c8b2f11e3a0ae0800 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0..28b192c9a 100644 -- 2.52.0 -From a2e0668c55f529d0abe95cf822bd4b86222f81bb Mon Sep 17 00:00:00 2001 +From 15b98d99608a548a88861ca74c5121765eff971d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42..f11b499e1 100644 -- 2.52.0 -From 98bb0310011338a2ab70d7536952ab1caf35e6a4 Mon Sep 17 00:00:00 2001 +From 314f2854360f28b1935c231df16d1c9989cf1ed3 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc..0976b2679 100644 -- 2.52.0 -From 534f5cb94af7f067f24c0a204e98b7d9a513cd45 Mon Sep 17 00:00:00 2001 +From 3539e5b2f72c8e2612dbd00721d38532af825fdb Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From 2094bfb94b193ec8f975f0d602aeef444d8880da Mon Sep 17 00:00:00 2001 +From e8a3976baa7abede7e32a5e6d447554e60775096 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From eba864a5f58712f7a6ce3555484092485637938a Mon Sep 17 00:00:00 2001 +From 47dc643dc3f19cb0a65780fbef8d414d348364e9 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb98..e03a1d8cd 100644 -- 2.52.0 -From f25ebe5b31578d2a4d4e66c3817ce4e0c9f412b8 Mon Sep 17 00:00:00 2001 +From 300fdc65c222ea24d03c61b94e4c55dc62ca1093 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index b2e99a4020..92c3e7b861 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From db3ec9540d493a473491fca1391969ad00212db8 Mon Sep 17 00:00:00 2001 +From fbc48842d119065e5a317d4c728ede0db106d436 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95..8914a922b 100644 -- 2.52.0 -From f2dcd89f3807295c28eb8248140735dca8b4a9d5 Mon Sep 17 00:00:00 2001 +From fc02ff3ec71b28dd4de353e4cd218c90d3c8782e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 0245c8b870..4774fa63e9 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 0dfdb22b626f288d56d9a41530ccdfb84a8baa47 Mon Sep 17 00:00:00 2001 +From 88cf5d00a596a8162e257070061451e10b8a5e3b Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index 8adabc931b..abfeddcdc7 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From ddec4ff683bbbb1e92e4fa30adcefe93b38c2cb0 Mon Sep 17 00:00:00 2001 +From cc0c3de6575789b23c2cea31f6c6acf7daf1e9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000..a171ea656 -- 2.52.0 -From 16174508fdd5cdfaebb39bc5c1747c09679b7a70 Mon Sep 17 00:00:00 2001 +From 7bde453c2a1559a75c0be13ed12b6dee59f1e809 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 From 0095ad7077137ae93338154075d18656275aef08 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sun, 18 Jan 2026 09:05:48 +0000 Subject: [PATCH 188/236] patches/v6.12: Update to v6.12.66 Generated 14 patches from linux-surface/kernel branch v6.12-surface Base version: v6.12.66 Branch: v6.12-surface Automatically generated patches using git-format-patchsets. --- patches/6.12/0001-secureboot.patch | 4 ++-- patches/6.12/0002-surface3-oemb.patch | 2 +- patches/6.12/0003-mwifiex.patch | 6 +++--- patches/6.12/0004-ath10k.patch | 2 +- patches/6.12/0005-ipts.patch | 10 +++++----- patches/6.12/0006-ithc.patch | 4 ++-- patches/6.12/0007-surface-sam-over-hid.patch | 4 ++-- patches/6.12/0008-surface-button.patch | 4 ++-- patches/6.12/0009-surface-typecover.patch | 6 +++--- patches/6.12/0010-surface-shutdown.patch | 2 +- patches/6.12/0011-surface-gpe.patch | 2 +- patches/6.12/0012-cameras.patch | 20 ++++++++++---------- patches/6.12/0013-amd-gpio.patch | 4 ++-- patches/6.12/0014-rtc.patch | 2 +- 14 files changed, 36 insertions(+), 36 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index e89ff8262a..d6af61df3b 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 63f1542405be6514cdb9504112379c22b748231c Mon Sep 17 00:00:00 2001 +From a2423a437bfdf0ed5dbfefb5027c6e540bc3468d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index b5c79f433..a1bbedd98 100644 -- 2.52.0 -From f8e1a06586181686a9ff1df26ac291134759d9cb Mon Sep 17 00:00:00 2001 +From 7d5bbf942248ee27275160eb50d7e4e08a61b8f9 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index 16a5aa36f0..a864fce9d0 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 5977a8fea25fd09161c5904e33ff90c9f0c36100 Mon Sep 17 00:00:00 2001 +From e99a1260bbafbbcddeff9b777bab48ff3e7e76cf Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index 00b4e1a556..c075421b10 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 1106cc5afb2f7db4ca9dc6359952766226a2fe67 Mon Sep 17 00:00:00 2001 +From b55306ce435ea996e721221e07643ac8d3f3d0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From edf9836d0f1d0eea5c98fd1e6de91da2c22472ad Mon Sep 17 00:00:00 2001 +From e2ec0841f3e94259534b0de6b4ac39d3d81653de Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 8f4b822de3c6817607f9c893d541fff7328ea1e4 Mon Sep 17 00:00:00 2001 +From 0a1ec5d7d9cd96cdb37402925d0b4e6610e66fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index 4660d02b75..69e1966336 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 23f0f61a46dc4a43f753a9ed38b27181e6d90510 Mon Sep 17 00:00:00 2001 +From 94abd2f89ef12048add8754aa23ab20ebc441687 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index 51496b1128..9efc18b201 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From fef08eee7169b1c1d65252985b201c83c07df382 Mon Sep 17 00:00:00 2001 +From 5a3a551bb17fe87de8d726adf5a299c862852ca8 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index a4f75dc36..e4a561b25 100644 +index fa30899a5..a1864dcb7 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index a4f75dc36..e4a561b25 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index bc0fc584a..51a91ef66 100644 +index 1e4edf896..61d1a8816 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -37,7 +37,7 @@ index bc0fc584a..51a91ef66 100644 -- 2.52.0 -From c0f4c7831822a7c7376dd159758420b1dd99f7a8 Mon Sep 17 00:00:00 2001 +From b5509f0f29c6d2965cf87b2817e0ea1b3770153d Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index c799cc67d..65adfc813 100644 -- 2.52.0 -From d924a0bfa4e787757f42c2011c7c8beaae1ee359 Mon Sep 17 00:00:00 2001 +From ffc2c79b83a3ef1aa12a12023d82f01369f98e35 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index e270a96ace..a5a56419be 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From fc5fa3bf68958afa207d59d442b42623173fe711 Mon Sep 17 00:00:00 2001 +From 2dec3490991faec7329071fb1da84fbb66ea6c33 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 066e4cd6e..7b320d09d 100644 -- 2.52.0 -From 3bd90d4e30ceeec7281e1781b35b783109736019 Mon Sep 17 00:00:00 2001 +From e391a07dc54b637bb96565766da220263b620411 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index eec5a1323d..e778599c33 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 9426284cef0fca02f23a75b33dc8ed39e116e3d1 Mon Sep 17 00:00:00 2001 +From aba6ab6b04bec689fd73f2bea505b58238d46f3d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index f43067f67..1761ca30e 100644 -- 2.52.0 -From 1eb7e55a8b1cca487474bc5b6efabfd20f1ff2ae Mon Sep 17 00:00:00 2001 +From a4dbbeb93034e310ddb73c4d1a8f5281eb3cb415 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index d88fcf4157..79384c314b 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From 72ac1d1bb27f99dca1df5b73062e02178e6c132a Mon Sep 17 00:00:00 2001 +From aafcec22ad9776d4448f09223fd26c826ab4406c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index 5c5d407fe..4e1bfe90e 100644 -- 2.52.0 -From 5c8a82f4b432a636005e19f1991185ed9eb1a8df Mon Sep 17 00:00:00 2001 +From 99238a763d217e20c12894ecd13b453151e6eb07 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index de55aee00d..ee649af4c5 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From ecb1c88302dacba1813b7e6b482920bd3ba9bbc3 Mon Sep 17 00:00:00 2001 +From fab95626dba115cb07de7d7fa797bffbb5f80c64 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c322d0c1d..52ae06afd 100644 -- 2.52.0 -From 2b744e2b904c695736bde325efe573af78077088 Mon Sep 17 00:00:00 2001 +From 1fda0cc37076dac0a11ce1a6c460f203b19e1a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 0e4cb0e66..26b551523 100644 -- 2.52.0 -From 05afdfa6c585bdffd6f35c470da129373fee45fb Mon Sep 17 00:00:00 2001 +From 12804521a6c821c27ab2bd8ac889ec68cda7a726 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index 40dfe38d96..d230be6bcd 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From e8e8f9dcf8a6d2981c196c3fdbe193a69b130d56 Mon Sep 17 00:00:00 2001 +From d765ff7ceea05518a0efa2339d996bbd40ba1560 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index bd688f7d2f..9ea95c4245 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From e321c203143de27d3bf7b4feb60ffa8f5db0d3bf Mon Sep 17 00:00:00 2001 +From 88132a4c037665666f6d9e0f4cb04692e173f1ac Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index c6c66b77b2..51f3f0fd89 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From 908376ffdfb35e8a7fc0b0741168f6981306b7e3 Mon Sep 17 00:00:00 2001 +From 025283349ce42174ae2991d156fd187c84bcc821 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ba98763ce..6021907ec 100644 -- 2.52.0 -From b50fa0e9a3d0a92ebe1845f4ae92798a9b602f27 Mon Sep 17 00:00:00 2001 +From 1cb705d86eab6e25171d9f934d4fc559a6fc1e9c Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 65adfc813..3dcabd6c5 100644 -- 2.52.0 -From 04808bcd8b873245f8878c5cb6a243f6a54a1c9b Mon Sep 17 00:00:00 2001 +From 7465075410aafe1c2e056837b892d6088fd7a23c Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 81ac4c691..f453c9043 100644 -- 2.52.0 -From 04d6cc0a730b23707e9eccc4a1e269ba027dc74b Mon Sep 17 00:00:00 2001 +From fed9d310d3c03130ed6db3a7785a3c1a9da7b109 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -277,7 +277,7 @@ index 9e69ac9cf..d6003198a 100644 -- 2.52.0 -From c561d9d986e0ec9972c93505d07754e700d83a62 Mon Sep 17 00:00:00 2001 +From 6b156036bf2fa490510465025d3368997eda6d6d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -316,7 +316,7 @@ index 3226888d7..3bfe45b76 100644 -- 2.52.0 -From 239cb784959f9c6751edcb8e30246f6e6947a3ac Mon Sep 17 00:00:00 2001 +From b46667943978af7b971a927b1b9bef2302a4d231 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -367,7 +367,7 @@ index f19c8adf2..923ed1b5a 100644 -- 2.52.0 -From c39a94ea4950d143cae4d8b8683017a89fc3377f Mon Sep 17 00:00:00 2001 +From 9dbe43576efe56749b172fb001f0ba09394a58d4 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -408,7 +408,7 @@ index f453c9043..b8ad6b413 100644 -- 2.52.0 -From 738ebac2df91aa10961af97aac1a9f0c339a5a19 Mon Sep 17 00:00:00 2001 +From 4e92c03760b866eeea7d13af3f8964c15682f468 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -449,7 +449,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From cd994d28d4edebc119ba0832c0e03995e53a1c95 Mon Sep 17 00:00:00 2001 +From 957b635554899ebc3c9777b205ca1dea8fd11799 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -700,7 +700,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From 1c3470f95886ee86781fa164a70ecc5f0b51dfa2 Mon Sep 17 00:00:00 2001 +From 40ce1bffe21b3945e0db8c93fe0420370e011c2d Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index 9b8aff6359..c1ce79d145 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From 4f72a8fba6496c49f0205e21772c7781f5f2e6d0 Mon Sep 17 00:00:00 2001 +From cb5c9d5aef5db7e1bda4a5f1b8d5b09263a0bd48 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 63adda8a1..00914222a 100644 -- 2.52.0 -From 796bdd93f2c2a1026d70100f304caef38662f361 Mon Sep 17 00:00:00 2001 +From d3762de8c84471626b6619138fa6eff0e04bdbe5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index b3a37af02d..8e5a42cec4 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From e2c9f4a3dfa5587ce98a77222db6b960c427d3fe Mon Sep 17 00:00:00 2001 +From d499d81c907450682259040cb23f4334c5291d34 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From 93d2dc325d1c34c12f3faa8f0e55775c96640b76 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sat, 24 Jan 2026 09:07:03 +0000 Subject: [PATCH 189/236] patches/v6.12: Update to v6.12.67 Generated 14 patches from linux-surface/kernel branch v6.12-surface Base version: v6.12.67 Branch: v6.12-surface Automatically generated patches using git-format-patchsets. --- patches/6.12/0001-secureboot.patch | 4 ++-- patches/6.12/0002-surface3-oemb.patch | 2 +- patches/6.12/0003-mwifiex.patch | 6 +++--- patches/6.12/0004-ath10k.patch | 2 +- patches/6.12/0005-ipts.patch | 6 +++--- patches/6.12/0006-ithc.patch | 4 ++-- patches/6.12/0007-surface-sam-over-hid.patch | 4 ++-- patches/6.12/0008-surface-button.patch | 4 ++-- patches/6.12/0009-surface-typecover.patch | 8 ++++---- patches/6.12/0010-surface-shutdown.patch | 2 +- patches/6.12/0011-surface-gpe.patch | 2 +- patches/6.12/0012-cameras.patch | 20 ++++++++++---------- patches/6.12/0013-amd-gpio.patch | 4 ++-- patches/6.12/0014-rtc.patch | 2 +- 14 files changed, 35 insertions(+), 35 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index d6af61df3b..076432d4cb 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From a2423a437bfdf0ed5dbfefb5027c6e540bc3468d Mon Sep 17 00:00:00 2001 +From b8a82d2a626465f4cdf912f855fbcef247eedc10 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index b5c79f433..a1bbedd98 100644 -- 2.52.0 -From 7d5bbf942248ee27275160eb50d7e4e08a61b8f9 Mon Sep 17 00:00:00 2001 +From 03705b5cfa7d87e162668f4cf47cb08a3aa002f1 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index a864fce9d0..19b84f6631 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From e99a1260bbafbbcddeff9b777bab48ff3e7e76cf Mon Sep 17 00:00:00 2001 +From 4ee64efe2fcd913b93a12054df1cb2cb4a524e33 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index c075421b10..9efa73e545 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From b55306ce435ea996e721221e07643ac8d3f3d0ec Mon Sep 17 00:00:00 2001 +From c3b97a265dd2e7a2bfa5d06ca4f5e7761b6e680d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From e2ec0841f3e94259534b0de6b4ac39d3d81653de Mon Sep 17 00:00:00 2001 +From 3f90405b93b79a88952fbe674d084ec2c1d348a6 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 0a1ec5d7d9cd96cdb37402925d0b4e6610e66fc9 Mon Sep 17 00:00:00 2001 +From 572b228bea431f8bcacf43abe99f22ddf5517d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index 69e1966336..549d477d4e 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 94abd2f89ef12048add8754aa23ab20ebc441687 Mon Sep 17 00:00:00 2001 +From 79852758c6d277f11456f1675e28edd544e83151 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index 9efc18b201..b0ebba1c9b 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From 5a3a551bb17fe87de8d726adf5a299c862852ca8 Mon Sep 17 00:00:00 2001 +From 016b54e98cb0d9bcae3efdffa17e28cb6e9e9b71 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 1e4edf896..61d1a8816 100644 -- 2.52.0 -From b5509f0f29c6d2965cf87b2817e0ea1b3770153d Mon Sep 17 00:00:00 2001 +From 812146c3632763ddfc8799683c181cf1a688fc9d Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index c799cc67d..65adfc813 100644 -- 2.52.0 -From ffc2c79b83a3ef1aa12a12023d82f01369f98e35 Mon Sep 17 00:00:00 2001 +From cd4b550350e259ac00d036e90b675108197077bb Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index a5a56419be..6648016809 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From 2dec3490991faec7329071fb1da84fbb66ea6c33 Mon Sep 17 00:00:00 2001 +From b4b53cb12fb1818201b29a9dca400e34f18f7494 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 066e4cd6e..7b320d09d 100644 -- 2.52.0 -From e391a07dc54b637bb96565766da220263b620411 Mon Sep 17 00:00:00 2001 +From fac2cb111a39ed2d58dd4222b21d61c46d3d0d96 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index e778599c33..38b71ea4f6 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From aba6ab6b04bec689fd73f2bea505b58238d46f3d Mon Sep 17 00:00:00 2001 +From 438ff08b86c52d04b6d3335bd104aa6855bef8b9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index f43067f67..1761ca30e 100644 -- 2.52.0 -From a4dbbeb93034e310ddb73c4d1a8f5281eb3cb415 Mon Sep 17 00:00:00 2001 +From 72729d60f3ea5601974e80e576c732ed8542f554 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index 79384c314b..2c0425891e 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From aafcec22ad9776d4448f09223fd26c826ab4406c Mon Sep 17 00:00:00 2001 +From fe02c79805a3d270bc2d8083d49a4968f1ac6d6b Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index 5c5d407fe..4e1bfe90e 100644 -- 2.52.0 -From 99238a763d217e20c12894ecd13b453151e6eb07 Mon Sep 17 00:00:00 2001 +From 6527332ea810dad56163535f4d4a7f7484aaca95 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index ee649af4c5..17ae9155d9 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From fab95626dba115cb07de7d7fa797bffbb5f80c64 Mon Sep 17 00:00:00 2001 +From 4e994b026c3480eaf8663a017462d6e805cf9077 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index c322d0c1d..52ae06afd 100644 +index 323a949bb..abc2cdecd 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -39,7 +39,7 @@ index c322d0c1d..52ae06afd 100644 -- 2.52.0 -From 1fda0cc37076dac0a11ce1a6c460f203b19e1a91 Mon Sep 17 00:00:00 2001 +From d69cc1c7e46d9e9aea52ee64500e43fa823f183e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 0e4cb0e66..26b551523 100644 -- 2.52.0 -From 12804521a6c821c27ab2bd8ac889ec68cda7a726 Mon Sep 17 00:00:00 2001 +From 52a3c2f1c8cd4521161c419daec8739612297a8a Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index d230be6bcd..cf410964ad 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From d765ff7ceea05518a0efa2339d996bbd40ba1560 Mon Sep 17 00:00:00 2001 +From c09a82503e99e9879188f0e459a22717fef6ecce Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index 9ea95c4245..a0bd9cd32d 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From 88132a4c037665666f6d9e0f4cb04692e173f1ac Mon Sep 17 00:00:00 2001 +From d3fd9b8e861c4e05f50c3062d93ab84ed8198a49 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index 51f3f0fd89..97ca07f7a5 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From 025283349ce42174ae2991d156fd187c84bcc821 Mon Sep 17 00:00:00 2001 +From b77dfed1149b9dfbfb112d4e6aa29a6eb6007840 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ba98763ce..6021907ec 100644 -- 2.52.0 -From 1cb705d86eab6e25171d9f934d4fc559a6fc1e9c Mon Sep 17 00:00:00 2001 +From 5d9d56716cc3f34562d11286cdbca59adfe20fd0 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 65adfc813..3dcabd6c5 100644 -- 2.52.0 -From 7465075410aafe1c2e056837b892d6088fd7a23c Mon Sep 17 00:00:00 2001 +From 2bde38758603b21b0b7f3eaf023f2778c2d50a68 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 81ac4c691..f453c9043 100644 -- 2.52.0 -From fed9d310d3c03130ed6db3a7785a3c1a9da7b109 Mon Sep 17 00:00:00 2001 +From 3d030f709639be08ac364a455cc46bdee615ffa8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -277,7 +277,7 @@ index 9e69ac9cf..d6003198a 100644 -- 2.52.0 -From 6b156036bf2fa490510465025d3368997eda6d6d Mon Sep 17 00:00:00 2001 +From 70f4fc9c7be17384d365cca714e3f6cd1f487ac1 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -316,7 +316,7 @@ index 3226888d7..3bfe45b76 100644 -- 2.52.0 -From b46667943978af7b971a927b1b9bef2302a4d231 Mon Sep 17 00:00:00 2001 +From da4e91f43bcbc995ca528ae1480f26dedcbc7e60 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -367,7 +367,7 @@ index f19c8adf2..923ed1b5a 100644 -- 2.52.0 -From 9dbe43576efe56749b172fb001f0ba09394a58d4 Mon Sep 17 00:00:00 2001 +From 24a0c28ce10e49979d41712c68a6698043fd22ad Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -408,7 +408,7 @@ index f453c9043..b8ad6b413 100644 -- 2.52.0 -From 4e92c03760b866eeea7d13af3f8964c15682f468 Mon Sep 17 00:00:00 2001 +From b62f4ea198626e8272626caa013e7b6baa3e1f4f Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -449,7 +449,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From 957b635554899ebc3c9777b205ca1dea8fd11799 Mon Sep 17 00:00:00 2001 +From 549dace780d55486e60f5350b568b53d186ac122 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -700,7 +700,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From 40ce1bffe21b3945e0db8c93fe0420370e011c2d Mon Sep 17 00:00:00 2001 +From 495d725951025e883e494ef1c1731e042a545363 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index c1ce79d145..ac5a40cf57 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From cb5c9d5aef5db7e1bda4a5f1b8d5b09263a0bd48 Mon Sep 17 00:00:00 2001 +From 31e8f1a75ddb7c0de5c1b63523f356bea7c6beed Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 63adda8a1..00914222a 100644 -- 2.52.0 -From d3762de8c84471626b6619138fa6eff0e04bdbe5 Mon Sep 17 00:00:00 2001 +From 29a7f6dbf6340689752fb699c060a8fe7b11231e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index 8e5a42cec4..20c658a8f9 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From d499d81c907450682259040cb23f4334c5291d34 Mon Sep 17 00:00:00 2001 +From 3a3721568ebb2ede3a4822a6e7f81b98db06946a Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From a1bcbcca9f0709ce9d7793a37e7d7ca234c533b2 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sat, 24 Jan 2026 09:14:51 +0000 Subject: [PATCH 190/236] patches/v6.18: Update to v6.18.7 Generated 16 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.7 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 4 ++-- patches/6.18/0002-surface3.patch | 4 ++-- patches/6.18/0003-mwifiex.patch | 6 +++--- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 6 +++--- patches/6.18/0006-ithc.patch | 4 ++-- patches/6.18/0007-surface-sam.patch | 4 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 4 ++-- patches/6.18/0009-surface-button.patch | 4 ++-- patches/6.18/0010-surface-typecover.patch | 8 ++++---- patches/6.18/0011-surface-shutdown.patch | 4 ++-- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 20 ++++++++++---------- patches/6.18/0014-amd-gpio.patch | 4 ++-- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 4 ++-- 16 files changed, 41 insertions(+), 41 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 4a6710ea07..0b7f832c8d 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From e3344768c391d3e4980996f6e02330fe797ba927 Mon Sep 17 00:00:00 2001 +From 65023019e757e470c4bd48765555ead3e5dcc187 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2..25848f886 100644 -- 2.52.0 -From cbfac26900958a27f0ef1ee7c0f29b331dbceee0 Mon Sep 17 00:00:00 2001 +From a44c5b828a5940a8a00777fa7ea63ca31c1962de Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index 8bddebbfc7..16e600622e 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 0e12e6b52c20b3b156629ad558f790e1103634f4 Mon Sep 17 00:00:00 2001 +From 7540349a64515324758354f03f3ebbe69751dd44 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0..0b930c91b 100644 -- 2.52.0 -From 3d036e8ef8991ae8d8f41448ad1bf69121b95fb4 Mon Sep 17 00:00:00 2001 +From 0ab087c8315d63949bcca3bc962591357108c565 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 9a9cb1a732..20e302c4ac 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From ea0e49ee498b64c010e74611aaf0b178d8016aa4 Mon Sep 17 00:00:00 2001 +From bb89bfa02608f36c7ed2b0274cd7238abd502f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From cdc60849a4e5f83427268d6daa651b4ee5059621 Mon Sep 17 00:00:00 2001 +From 28a6aba5caa6375b043c6911255153d6b3467f75 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 6e8dfacc75693497fca42bc6a2e83a709c28c793 Mon Sep 17 00:00:00 2001 +From e9742fa6b209a09dfa2ca3a54d3b0fce4d753e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index 2edf05b8a2..e3790d28ea 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 321436678300fdb5cccf60f692aadc8b9b0d02b5 Mon Sep 17 00:00:00 2001 +From 0c29379773e77fabade4af9340a46ad70024611b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 1ea21e8f47..4f2c57af33 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 7d4b029eae825c38b06628dca4dfb094abfdf466 Mon Sep 17 00:00:00 2001 +From cf7a77387b7ba7e212ece7b5eb49579667219942 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e56955..c19dfba54 100644 -- 2.52.0 -From 89781c65888bc9b3d86c746e81368f88cac13ac4 Mon Sep 17 00:00:00 2001 +From fe3d622e306ca176f40588634022bea09fe7a9bf Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e236c7ec2..9e31a5fe1 100644 -- 2.52.0 -From 6e0741b765c1db5a62bb07c9b8701fa8d8605f5a Mon Sep 17 00:00:00 2001 +From 8b3cf2142ffa659dab6041ede28dae1b923a4831 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index cfda0c38ef..0912eb834c 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From 7e9b8475a04d1ce2957cdd8ea777158d21b0c480 Mon Sep 17 00:00:00 2001 +From 7d653dd37c82eceddb940978a1d92bf64bbd99c7 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9..c78806d35 100644 -- 2.52.0 -From d0648197b84aa176988d669969b60b8809d32e7e Mon Sep 17 00:00:00 2001 +From 6db881de95e570982525b040d5411aed42cf9fc2 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index a4470373cf..baaa8bfc96 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 136fda6da11f8108d830afad579148236ba06dfd Mon Sep 17 00:00:00 2001 +From 0e99b3cf2d60d2e62d35ace1cd7c6e8972f87a3a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000..f6c17c4e9 -- 2.52.0 -From c12f4b52dffee6c0c45ac8034155a2a942791bfa Mon Sep 17 00:00:00 2001 +From d517dea0845c01308edb3b219867886470e363db Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 4c2abf4ef8..6d609d4537 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From df4c86a5039ca68258a22f32ead2d35d55312ecf Mon Sep 17 00:00:00 2001 +From 7ed908f77f3703a80af9163376a0d257688fe63d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a2..070c36637 100644 -- 2.52.0 -From 3821285cceabe2ca3ae176a2702a9183bd2967ca Mon Sep 17 00:00:00 2001 +From 990d8e44668a9a8fa90c998cca066877f0e094e8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 4746a6dc66..9fbd4442e6 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 358f7910e7d6b687a42b29bb7a9c33726604ea61 Mon Sep 17 00:00:00 2001 +From 5435570ea3009568161af7bdfd7720b664d1140c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c..43b5d5638 100644 -- 2.52.0 -From 91459003685804cdf68739d5f5104609ca39ccc6 Mon Sep 17 00:00:00 2001 +From a84a014b4bdf583f23acd8056ce23464a4d4ca47 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index eaee1254f6..dfcfd0a23a 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 7056ab9026176ab860df770eed65cbe08573ee55 Mon Sep 17 00:00:00 2001 +From 0a8c670d0a5e2db12cea9e192e48e2cfb1a86973 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index 47f589c41..6b00aec67 100644 +index c4d85089d..3d0d35c72 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -39,7 +39,7 @@ index 47f589c41..6b00aec67 100644 -- 2.52.0 -From 67e9cc13be702451b2d83c9542c7fd5ab8efcf24 Mon Sep 17 00:00:00 2001 +From ff53718ae3c358eb6da5dcd77b426fc7543d0dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 179dc316b..7d644e1c4 100644 -- 2.52.0 -From defac4657f8e5d3f44d8ebe3d02d9e8b39601e55 Mon Sep 17 00:00:00 2001 +From 1a6aa250e57410a9f013a2d46cd74a6e327a4046 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index bdb6d71f6f..a9175630b4 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 443f7de4ee944e938ca0c90b89152bb1fce8aa31 Mon Sep 17 00:00:00 2001 +From 67b13eaca5b31245a5217682083642ad5d1515fc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index bf97d49c2..90eead93d 100644 -- 2.52.0 -From 503713abb5374b1fc12c26972e18de70bf00250c Mon Sep 17 00:00:00 2001 +From a78e463c5d6d9b007d8d45719df365c9f9d84be3 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index b113847f96..aa61cbf2d3 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 4df121228542c37c2771e470147ba6d3f88ee6cc Mon Sep 17 00:00:00 2001 +From c8d2a9c279cb950a3c8d0793386592c6fa48de0e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index aaa9113e8a..0aec7f3584 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From c8a93f5e492ef439cc44383b2000a02802f2638e Mon Sep 17 00:00:00 2001 +From e286569044ab46525518d0e6b6c9060ffaef2ab6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2..a6bad2679 100644 -- 2.52.0 -From 6c66043178d66f7b67a080cba9759be06cde03a8 Mon Sep 17 00:00:00 2001 +From f21f1ebd6e35d221201e1cdd8366d52d116dd93b Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 9e31a5fe1..bdd32551c 100644 -- 2.52.0 -From c62706701d19ecb98060af9204dd0fb254dca2f5 Mon Sep 17 00:00:00 2001 +From 7dabd26ac8d9da4268d0c0e2c86e6c25aff1d3f8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 013340569..9e0763bdc 100644 -- 2.52.0 -From b4af7c93a1a456f669cdca4c8b2f11e3a0ae0800 Mon Sep 17 00:00:00 2001 +From e2d439ead544873d9408d8eb5670b00cf3f4dd41 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0..28b192c9a 100644 -- 2.52.0 -From 15b98d99608a548a88861ca74c5121765eff971d Mon Sep 17 00:00:00 2001 +From ad42c93969536b0baa79e3645fb40f8843b99e99 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42..f11b499e1 100644 -- 2.52.0 -From 314f2854360f28b1935c231df16d1c9989cf1ed3 Mon Sep 17 00:00:00 2001 +From 7a237ebefcf137537da3747fa057a9755449f79b Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc..0976b2679 100644 -- 2.52.0 -From 3539e5b2f72c8e2612dbd00721d38532af825fdb Mon Sep 17 00:00:00 2001 +From 2b4b5979e609ff1a8585e04cb7409b8130bb1a50 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From e8a3976baa7abede7e32a5e6d447554e60775096 Mon Sep 17 00:00:00 2001 +From 261989a64ab1c651f2c79e300d1ed83c5f9a24c2 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From 47dc643dc3f19cb0a65780fbef8d414d348364e9 Mon Sep 17 00:00:00 2001 +From 6b054d0f9cc77fbce385ffdddb0ada60823e2d21 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb98..e03a1d8cd 100644 -- 2.52.0 -From 300fdc65c222ea24d03c61b94e4c55dc62ca1093 Mon Sep 17 00:00:00 2001 +From e39fb77521f13219b27d0e39e2a77a84b17ded58 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 92c3e7b861..7204d87a40 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From fbc48842d119065e5a317d4c728ede0db106d436 Mon Sep 17 00:00:00 2001 +From d3d85f0c39e70ea972456bad4c7447b5eb207db3 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95..8914a922b 100644 -- 2.52.0 -From fc02ff3ec71b28dd4de353e4cd218c90d3c8782e Mon Sep 17 00:00:00 2001 +From 78dd2102bdfd831dd957e3f4c8710eb6ded17f2b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 4774fa63e9..9c6f909593 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 88cf5d00a596a8162e257070061451e10b8a5e3b Mon Sep 17 00:00:00 2001 +From 6767aeecda4156c7d5e82f3910ff7b23ec59b318 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index abfeddcdc7..29b2bc0c91 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From cc0c3de6575789b23c2cea31f6c6acf7daf1e9cf Mon Sep 17 00:00:00 2001 +From 56bdbcbcabe6116da57bcd583a2101f68815fabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000..a171ea656 -- 2.52.0 -From 7bde453c2a1559a75c0be13ed12b6dee59f1e809 Mon Sep 17 00:00:00 2001 +From 5d71ba3d69436b26d4940d73f9a55eda46394b15 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 From b674f4e882bf77afa27cb3b60b4c6850ac5a4e96 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sun, 25 Jan 2026 20:14:35 +0000 Subject: [PATCH 191/236] patches/v6.18: Update to v6.18.7 Generated 17 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.7 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0017-powercap.patch | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/patches/6.18/0017-powercap.patch b/patches/6.18/0017-powercap.patch index 8b79b0f058..207ee9e545 100644 --- a/patches/6.18/0017-powercap.patch +++ b/patches/6.18/0017-powercap.patch @@ -1,4 +1,4 @@ -From a1c886a619ddf7245f2a5cc51404baacb92c29c6 Mon Sep 17 00:00:00 2001 +From 6186a782293d3eaa335d0e32048d2b1dd32d4369 Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Wed, 14 Jan 2026 20:31:38 -0500 Subject: [PATCH] powercap: intel_rapl: Add PL4 support for Ice Lake @@ -8,15 +8,16 @@ boot/resume. Userspace needs to be able to restore the correct value. Link: https://github.com/linux-surface/linux-surface/issues/706 Signed-off-by: Daniel Tang +Patchset: powercap --- drivers/powercap/intel_rapl_msr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c -index 9a7e150b3536..a2bc0a9c1e10 100644 +index c6b9a7deb..e82724768 100644 --- a/drivers/powercap/intel_rapl_msr.c +++ b/drivers/powercap/intel_rapl_msr.c -@@ -162,6 +162,7 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra) +@@ -140,6 +140,7 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra) /* List of verified CPUs. */ static const struct x86_cpu_id pl4_support_ids[] = { @@ -25,5 +26,5 @@ index 9a7e150b3536..a2bc0a9c1e10 100644 X86_MATCH_VFM(INTEL_ALDERLAKE, NULL), X86_MATCH_VFM(INTEL_ALDERLAKE_L, NULL), -- -2.51.0 +2.52.0 From a036e4c31300900ba02a7b7c8b1602c5a2bd5680 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 25 Jan 2026 21:25:13 +0100 Subject: [PATCH 192/236] Update Arch kernel to v6.18.7 --- pkg/arch/kernel/0017-powercap.patch | 1 + pkg/arch/kernel/PKGBUILD | 38 +++++++++++++++-------------- 2 files changed, 21 insertions(+), 18 deletions(-) create mode 120000 pkg/arch/kernel/0017-powercap.patch diff --git a/pkg/arch/kernel/0017-powercap.patch b/pkg/arch/kernel/0017-powercap.patch new file mode 120000 index 0000000000..4e00a36f8d --- /dev/null +++ b/pkg/arch/kernel/0017-powercap.patch @@ -0,0 +1 @@ +../../../patches/6.18/0017-powercap.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 3bdb34f182..e783a3bc3e 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.18.5.arch1 +pkgver=6.18.7.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -58,32 +58,34 @@ source=( 0014-amd-gpio.patch 0015-rtc.patch 0016-hid-surface.patch + 0017-powercap.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('b5d871948897d5e498d057e1536f3777c00f441e668b9a7febeb717435a0941b' +sha256sums=('4323793a7e149c18632671b692d1f90ec991c2097167d9de8413636ae432073c' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '5ff34a1fb3f64692bc37968e8574fe87cc67febed0ca0dc370b56185214c91fc' - '5ee83652d8475a092c3c20cdaa3f4389da847b2b4a016e3d8fbd461d09ec6edb' - 'add901e1529eb75b9e1ba33eb01a9c8939db79fb9127aaa8302b8699cfb529bb' - '2a51a027d6d6da802f3eecaca93c79adb83a3abe3e03b26737070e50aff15e96' - '8511e16a3c492bee1d3dcc2dee23d3150ece3dee4e44d42803a5358eac7bf151' - '76a55691ccb7739b7ff7d2db8e7853953abdec4f20d6feb08641a3ca0c3b0228' - 'f721b66d0a75129202165a27ef682946964d8e3835ae9a69a0fb43909d14166b' - '5b81488ae1a437c2e31032331c8e7700cdfe58c3bd2cd559c039c2860caeab5c' - '13149b4239df2d38a1449e1cc608548f5f449bc9cad806acf3eaa39ce539b6b6' - '0245dbf371829f251fbe1d07f519c22d5198bb72b8c00ba76bbbe11f154a94ee' - 'dd6a53d3c65a5a24078c880bfa010b074b9de27983e08290664b1f50908e86dd' - '9feef378c2838706b41ae5f8b48f0aa4e219532a02be236964b007636e1abb67' - '192ed7cb4d0efee35e7a638b6e650fa6ac99e594fc34f475fddac86ddeb040ed' - 'd3f6df3574ba20915d1b55bf9bb48c5f445a5d9bd291fd3eac30714cd4df2b8a' - 'ad9fca07451fe81f058c89d7f1dc8524dd02e5282a0ddc243f8a35c0a57c4df9' - '83dea9c314f928a332a64b6fd004af25d295f8ae1041d4218cb0130a2e35a11c') + '504062f0ed5f4bd238ff1775ba809ce2d10e675902532c1a0796bc3f2a5b47aa' + '0ec23c28f5ada5df2872806efcc2ef5b1ec225891112c9eb8dd2b0b6b507c923' + '5cba99600cea14ae8b8e512e79e14897b47a668c469a942752b36bb3bfa1f43a' + '82062e65aa29d7a5900ce9096e94a670da9eeac405b7bcfe8ff7a299147d044a' + '914d2dc9724c7e9f50948680db4291646d9ebf97ee8f94c819c77fd5a15a6bf9' + 'baa00e12c12e10f86857857977183a4c144a2f6100be9aab85de436510010a8b' + '0243436e97a99881b8e8974fe0cfce14b0d80e5ad9be82c527e9616412a494ce' + '6dd0dda89c4f76a6ba51e2b5107f0d70866ffadea0918ebca5f4a4ed57f7eb21' + 'd9beeb6b18cafca90445adb0897d6033684060852ca45634595707e62898ba75' + '085f08e1fe5c505f6a8e95819e69e3144ace6954260131c9d0910beac1176733' + '96f3c35d2a763346d02ce212747e4944dc45bfb2e91b6c61fe8e4d60a0634c95' + '7e50bb11c051579042a172f7563bc1c0d33cc7a649334ec1f428641e10b0c4a5' + 'd8427605a6805152517d7edc14c06dd86f8b004d6cfe11ea33177938c5720a7c' + 'c34120274bacbd5e0e7c7a0f8db420bf5da0773e05752e1510324469d48f4f53' + 'ba6be94290bcfcd6614fefad4b9418f812699a7a340a4edd218628324c2d2c9d' + 'fde839050a7648ff1b8782df364e1e62f6a2b575e437e04043c7179d74cbf157' + 'c9350beb089cb23b22ff156521575979d23abaafc3adc69d5068ebc303cfa0fe') export KBUILD_BUILD_HOST=archlinux From d5a4031f5cfdbcf2bd5106e947dcc9ea5d63eee5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 25 Jan 2026 21:29:48 +0100 Subject: [PATCH 193/236] Update Debian kernel to v6.18.7 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 968dff8ed4..7f000371e3 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.18.5" +KERNEL_VERSION="6.18.7" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From f42be10ad19bbc2502c063d13cf68911ac4c185c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 25 Jan 2026 21:30:39 +0100 Subject: [PATCH 194/236] Update Fedora kernels to v6.18.7 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index b1b74d9ce2..efbee59e49 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.18.5-0" +PACKAGE_TAG = "kernel-6.18.7-0" ## ## The release number of the modified kernel package. From fb9befd3c654d0a8906639acdba0141dd5a99576 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sat, 31 Jan 2026 09:09:31 +0000 Subject: [PATCH 195/236] patches/v6.12: Update to v6.12.68 Generated 14 patches from linux-surface/kernel branch v6.12-surface Base version: v6.12.68 Branch: v6.12-surface Automatically generated patches using git-format-patchsets. --- patches/6.12/0001-secureboot.patch | 4 ++-- patches/6.12/0002-surface3-oemb.patch | 2 +- patches/6.12/0003-mwifiex.patch | 6 +++--- patches/6.12/0004-ath10k.patch | 2 +- patches/6.12/0005-ipts.patch | 6 +++--- patches/6.12/0006-ithc.patch | 4 ++-- patches/6.12/0007-surface-sam-over-hid.patch | 4 ++-- patches/6.12/0008-surface-button.patch | 4 ++-- patches/6.12/0009-surface-typecover.patch | 6 +++--- patches/6.12/0010-surface-shutdown.patch | 2 +- patches/6.12/0011-surface-gpe.patch | 2 +- patches/6.12/0012-cameras.patch | 20 ++++++++++---------- patches/6.12/0013-amd-gpio.patch | 4 ++-- patches/6.12/0014-rtc.patch | 2 +- 14 files changed, 34 insertions(+), 34 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index 076432d4cb..171f300330 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From b8a82d2a626465f4cdf912f855fbcef247eedc10 Mon Sep 17 00:00:00 2001 +From 83fb412e5ce1df11aae62b316282cdf3cab99301 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index b5c79f433..a1bbedd98 100644 -- 2.52.0 -From 03705b5cfa7d87e162668f4cf47cb08a3aa002f1 Mon Sep 17 00:00:00 2001 +From fe63d5758097d8f030140b054ac6644107c956b9 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index 19b84f6631..5cfaf178b2 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 4ee64efe2fcd913b93a12054df1cb2cb4a524e33 Mon Sep 17 00:00:00 2001 +From 8d20e56573c6b88f5e9d26c9b48194a69b1b263d Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index 9efa73e545..4f90bcba1f 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From c3b97a265dd2e7a2bfa5d06ca4f5e7761b6e680d Mon Sep 17 00:00:00 2001 +From 455aa655eca2c1531e9e719dffe3b8a74b4cdcdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From 3f90405b93b79a88952fbe674d084ec2c1d348a6 Mon Sep 17 00:00:00 2001 +From 4004203431ddaaee61dd98e07b6df4518e4c70f8 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 572b228bea431f8bcacf43abe99f22ddf5517d13 Mon Sep 17 00:00:00 2001 +From 8b32ce1c516120ff04578d2984c0a41b6b2eb32b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index 549d477d4e..3889fa33f7 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 79852758c6d277f11456f1675e28edd544e83151 Mon Sep 17 00:00:00 2001 +From 1272e0f2951f6d2deff64aaea6bcb9c1f1ec5fa5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index b0ebba1c9b..2554d07772 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From 016b54e98cb0d9bcae3efdffa17e28cb6e9e9b71 Mon Sep 17 00:00:00 2001 +From 18382716c95dcbb8aef8394c695ed7302b237b52 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 1e4edf896..61d1a8816 100644 -- 2.52.0 -From 812146c3632763ddfc8799683c181cf1a688fc9d Mon Sep 17 00:00:00 2001 +From 02c872988f7201479070a3f10b4518161556368a Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index c799cc67d..65adfc813 100644 -- 2.52.0 -From cd4b550350e259ac00d036e90b675108197077bb Mon Sep 17 00:00:00 2001 +From 1880d8e4133705698ca7aa18f5b65c7c92ba2de9 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index 6648016809..729014279f 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From b4b53cb12fb1818201b29a9dca400e34f18f7494 Mon Sep 17 00:00:00 2001 +From 89f46673f771eb27289638133bd55c70dfc953d6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 066e4cd6e..7b320d09d 100644 -- 2.52.0 -From fac2cb111a39ed2d58dd4222b21d61c46d3d0d96 Mon Sep 17 00:00:00 2001 +From 3e42ef9a26315313a2dc7722645e45d3f2e86646 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index 38b71ea4f6..973b965457 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 438ff08b86c52d04b6d3335bd104aa6855bef8b9 Mon Sep 17 00:00:00 2001 +From 9a901fb49e8eeaaf6e32e33d2fb1595a5b68391d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index f43067f67..1761ca30e 100644 -- 2.52.0 -From 72729d60f3ea5601974e80e576c732ed8542f554 Mon Sep 17 00:00:00 2001 +From 910bd8dce5db8f99e7cc20f5a773ccc14092de00 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index 2c0425891e..8362fafb34 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From fe02c79805a3d270bc2d8083d49a4968f1ac6d6b Mon Sep 17 00:00:00 2001 +From 833e3db5906a61edde1c514283c500873286192a Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index 5c5d407fe..4e1bfe90e 100644 -- 2.52.0 -From 6527332ea810dad56163535f4d4a7f7484aaca95 Mon Sep 17 00:00:00 2001 +From 8821ccb1052dbc6af294c56742662455cd7686ca Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index 17ae9155d9..d3d0f2d833 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From 4e994b026c3480eaf8663a017462d6e805cf9077 Mon Sep 17 00:00:00 2001 +From b672d83af9647f51ff73a8158d626898a46e8ec7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 323a949bb..abc2cdecd 100644 -- 2.52.0 -From d69cc1c7e46d9e9aea52ee64500e43fa823f183e Mon Sep 17 00:00:00 2001 +From f91864077f6380de6d73fea2b935cfe8d0ec0c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 0e4cb0e66..26b551523 100644 -- 2.52.0 -From 52a3c2f1c8cd4521161c419daec8739612297a8a Mon Sep 17 00:00:00 2001 +From 9a1db7e264b5484d7281b8b8f352222e77017acb Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index cf410964ad..379910ea96 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From c09a82503e99e9879188f0e459a22717fef6ecce Mon Sep 17 00:00:00 2001 +From 50751f30b80fdf8da3931ea45bff613e9fff20e1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index a0bd9cd32d..460f005b6b 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From d3fd9b8e861c4e05f50c3062d93ab84ed8198a49 Mon Sep 17 00:00:00 2001 +From 0d638821f83be823bc8345da67dc575b4f63a8a4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index 97ca07f7a5..a8934ddf1a 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From b77dfed1149b9dfbfb112d4e6aa29a6eb6007840 Mon Sep 17 00:00:00 2001 +From 7425a395008ba82583190496b0d5b931650273de Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ba98763ce..6021907ec 100644 -- 2.52.0 -From 5d9d56716cc3f34562d11286cdbca59adfe20fd0 Mon Sep 17 00:00:00 2001 +From da323c3272093ad7d5d24ec67ff5e255389ea829 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 65adfc813..3dcabd6c5 100644 -- 2.52.0 -From 2bde38758603b21b0b7f3eaf023f2778c2d50a68 Mon Sep 17 00:00:00 2001 +From b30bb045b4d67722312ba305f9303b8cf2dcbf74 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 81ac4c691..f453c9043 100644 -- 2.52.0 -From 3d030f709639be08ac364a455cc46bdee615ffa8 Mon Sep 17 00:00:00 2001 +From e1cef1af2572cb49bc479c781ea313e63a5f1dc6 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -277,7 +277,7 @@ index 9e69ac9cf..d6003198a 100644 -- 2.52.0 -From 70f4fc9c7be17384d365cca714e3f6cd1f487ac1 Mon Sep 17 00:00:00 2001 +From 299c771ba77c2eddf8704a86e7bab43d83d58d13 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -316,7 +316,7 @@ index 3226888d7..3bfe45b76 100644 -- 2.52.0 -From da4e91f43bcbc995ca528ae1480f26dedcbc7e60 Mon Sep 17 00:00:00 2001 +From 30c528c9306fc89ccc0b9494de692ee2eb547f8e Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -367,7 +367,7 @@ index f19c8adf2..923ed1b5a 100644 -- 2.52.0 -From 24a0c28ce10e49979d41712c68a6698043fd22ad Mon Sep 17 00:00:00 2001 +From 5d50a766308660d2ae03100f2d63689825cc39d2 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -408,7 +408,7 @@ index f453c9043..b8ad6b413 100644 -- 2.52.0 -From b62f4ea198626e8272626caa013e7b6baa3e1f4f Mon Sep 17 00:00:00 2001 +From 7591d1c40fb71d4b8a7246d9fcc035f6339b82d5 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -449,7 +449,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From 549dace780d55486e60f5350b568b53d186ac122 Mon Sep 17 00:00:00 2001 +From 1f4c6b08455a323956c12a9c69fb809e0c1e4a92 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -700,7 +700,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From 495d725951025e883e494ef1c1731e042a545363 Mon Sep 17 00:00:00 2001 +From c44aa32a7a57e44fb992dcdfa30dd2d5723e15ec Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index ac5a40cf57..1b2c0c8fde 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From 31e8f1a75ddb7c0de5c1b63523f356bea7c6beed Mon Sep 17 00:00:00 2001 +From 949bb8d4c19b6f83e581980373f0cc6d17a1985f Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 63adda8a1..00914222a 100644 -- 2.52.0 -From 29a7f6dbf6340689752fb699c060a8fe7b11231e Mon Sep 17 00:00:00 2001 +From 07eb4f50c84102985c37e930e6596bffe93ece1d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index 20c658a8f9..e857688e45 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From 3a3721568ebb2ede3a4822a6e7f81b98db06946a Mon Sep 17 00:00:00 2001 +From d7276bb3fd747ae88c0638c294e9f3e8ab60d6cd Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From 54cbb6c15e5fd226f8ff19af15e7c3dc3eb86f3d Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sat, 31 Jan 2026 09:18:08 +0000 Subject: [PATCH 196/236] patches/v6.18: Update to v6.18.8 Generated 17 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.8 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 4 ++-- patches/6.18/0002-surface3.patch | 4 ++-- patches/6.18/0003-mwifiex.patch | 6 +++--- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 6 +++--- patches/6.18/0006-ithc.patch | 4 ++-- patches/6.18/0007-surface-sam.patch | 4 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 4 ++-- patches/6.18/0009-surface-button.patch | 4 ++-- patches/6.18/0010-surface-typecover.patch | 6 +++--- patches/6.18/0011-surface-shutdown.patch | 4 ++-- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 20 ++++++++++---------- patches/6.18/0014-amd-gpio.patch | 4 ++-- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 4 ++-- patches/6.18/0017-powercap.patch | 2 +- 17 files changed, 41 insertions(+), 41 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 0b7f832c8d..e486187ba9 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 65023019e757e470c4bd48765555ead3e5dcc187 Mon Sep 17 00:00:00 2001 +From 000648f4f90818dc20b4bebfcddc3a9f3803ff15 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2..25848f886 100644 -- 2.52.0 -From a44c5b828a5940a8a00777fa7ea63ca31c1962de Mon Sep 17 00:00:00 2001 +From e041d8263d093f2d2d5123d246e220c53e6ca57b Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index 16e600622e..b7faaf7ad9 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 7540349a64515324758354f03f3ebbe69751dd44 Mon Sep 17 00:00:00 2001 +From e9e6b39423574dbf8c69dceb448a7d025c76a9d7 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0..0b930c91b 100644 -- 2.52.0 -From 0ab087c8315d63949bcca3bc962591357108c565 Mon Sep 17 00:00:00 2001 +From 4a07615e2ebf577c6e71b51b7badbbba4d633981 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 20e302c4ac..30e46b5e37 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From bb89bfa02608f36c7ed2b0274cd7238abd502f56 Mon Sep 17 00:00:00 2001 +From 7e1bb52229f6ce7a4a8b3feeee858c6ccf9eaa79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From 28a6aba5caa6375b043c6911255153d6b3467f75 Mon Sep 17 00:00:00 2001 +From 9c0afb16977536994d235fa7a67344e79f9f56d5 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From e9742fa6b209a09dfa2ca3a54d3b0fce4d753e49 Mon Sep 17 00:00:00 2001 +From 3767d1a91caf6f15f562b9d1742d0e4ac30ab18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index e3790d28ea..0006a259d5 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 0c29379773e77fabade4af9340a46ad70024611b Mon Sep 17 00:00:00 2001 +From c063b83e99378d0f2f2820291ac0d96f196e080c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 4f2c57af33..db12aea6fb 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From cf7a77387b7ba7e212ece7b5eb49579667219942 Mon Sep 17 00:00:00 2001 +From 8b7cb164383dc09f88305bfbe2828edc5ca8456e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e56955..c19dfba54 100644 -- 2.52.0 -From fe3d622e306ca176f40588634022bea09fe7a9bf Mon Sep 17 00:00:00 2001 +From 7c3015468063bb7a0aa8b51c49290ed1542bd89c Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e236c7ec2..9e31a5fe1 100644 -- 2.52.0 -From 8b3cf2142ffa659dab6041ede28dae1b923a4831 Mon Sep 17 00:00:00 2001 +From bdf9e4ac66246e18f06cae402728aef34e612c33 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index 0912eb834c..fa98034dc7 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From 7d653dd37c82eceddb940978a1d92bf64bbd99c7 Mon Sep 17 00:00:00 2001 +From 329dbd98a2f7dcab6ebce425af6c708319aa352d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9..c78806d35 100644 -- 2.52.0 -From 6db881de95e570982525b040d5411aed42cf9fc2 Mon Sep 17 00:00:00 2001 +From b8585c954e2f495be9ed798528f348ab3fda65d2 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index baaa8bfc96..4b7e4bc395 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 0e99b3cf2d60d2e62d35ace1cd7c6e8972f87a3a Mon Sep 17 00:00:00 2001 +From 878de2f4b354ad17071c51b43a4c9b873a5c52dd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000..f6c17c4e9 -- 2.52.0 -From d517dea0845c01308edb3b219867886470e363db Mon Sep 17 00:00:00 2001 +From 6e8dc33ef616c446653e9b362e3d73b130729190 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 6d609d4537..4ec1b82967 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 7ed908f77f3703a80af9163376a0d257688fe63d Mon Sep 17 00:00:00 2001 +From a2b8be244e3bca9055d360ebc90471d7418c52ab Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a2..070c36637 100644 -- 2.52.0 -From 990d8e44668a9a8fa90c998cca066877f0e094e8 Mon Sep 17 00:00:00 2001 +From 96d18f6989c750179269ae199f4a1f32aa3c3059 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 9fbd4442e6..4de12498da 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 5435570ea3009568161af7bdfd7720b664d1140c Mon Sep 17 00:00:00 2001 +From 9bea2a09219c5b3acf4c7ba8b328b1675e964bb7 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c..43b5d5638 100644 -- 2.52.0 -From a84a014b4bdf583f23acd8056ce23464a4d4ca47 Mon Sep 17 00:00:00 2001 +From 37a68e90e88ad5f17b65dd6e74b91907b9f3d658 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index dfcfd0a23a..423b78c5c6 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 0a8c670d0a5e2db12cea9e192e48e2cfb1a86973 Mon Sep 17 00:00:00 2001 +From 5f0114d0663f471a37224f81d9decbb4671e5664 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c4d85089d..3d0d35c72 100644 -- 2.52.0 -From ff53718ae3c358eb6da5dcd77b426fc7543d0dc1 Mon Sep 17 00:00:00 2001 +From e69f8b3a80a4684de31ea21f23211ed2acaeed35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 179dc316b..7d644e1c4 100644 -- 2.52.0 -From 1a6aa250e57410a9f013a2d46cd74a6e327a4046 Mon Sep 17 00:00:00 2001 +From e01885e989e3f0f4d8ccef483ae6f7b0896d1cbb Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index a9175630b4..4c4acb7df9 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 67b13eaca5b31245a5217682083642ad5d1515fc Mon Sep 17 00:00:00 2001 +From 22ea5007c2f6c4a45778e5719fe68f98f6a128b5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index bf97d49c2..90eead93d 100644 -- 2.52.0 -From a78e463c5d6d9b007d8d45719df365c9f9d84be3 Mon Sep 17 00:00:00 2001 +From 5f5fe5c30fed707408e995b5f9b4fd70850502ed Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index aa61cbf2d3..98d6c15ab6 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From c8d2a9c279cb950a3c8d0793386592c6fa48de0e Mon Sep 17 00:00:00 2001 +From 544ebf521bb51bc76bbb53be59dd343553238299 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index 0aec7f3584..90be19c993 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From e286569044ab46525518d0e6b6c9060ffaef2ab6 Mon Sep 17 00:00:00 2001 +From 4efcc8606f380b191a190c0dea444783a76b8e80 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2..a6bad2679 100644 -- 2.52.0 -From f21f1ebd6e35d221201e1cdd8366d52d116dd93b Mon Sep 17 00:00:00 2001 +From 9c8c596646650ffc4e2aec66b64bfc53bd1064d6 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 9e31a5fe1..bdd32551c 100644 -- 2.52.0 -From 7dabd26ac8d9da4268d0c0e2c86e6c25aff1d3f8 Mon Sep 17 00:00:00 2001 +From fdf85e34e0cd9707edead5c6629af8297bfe799e Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 013340569..9e0763bdc 100644 -- 2.52.0 -From e2d439ead544873d9408d8eb5670b00cf3f4dd41 Mon Sep 17 00:00:00 2001 +From f504b621cd3f73e83fa62117d4bef7c623d16859 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0..28b192c9a 100644 -- 2.52.0 -From ad42c93969536b0baa79e3645fb40f8843b99e99 Mon Sep 17 00:00:00 2001 +From 9389eecd77c1bd3c64a65e53d51bd872bd08b48a Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42..f11b499e1 100644 -- 2.52.0 -From 7a237ebefcf137537da3747fa057a9755449f79b Mon Sep 17 00:00:00 2001 +From b2ba431af4ef8243a28baef5f221a94343b8ea01 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc..0976b2679 100644 -- 2.52.0 -From 2b4b5979e609ff1a8585e04cb7409b8130bb1a50 Mon Sep 17 00:00:00 2001 +From 3a7716a4105e214a32ea0f1d2b41bbdecedc6f7f Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From 261989a64ab1c651f2c79e300d1ed83c5f9a24c2 Mon Sep 17 00:00:00 2001 +From 9a52132b23e671cc90c43857e933395f8bec3387 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From 6b054d0f9cc77fbce385ffdddb0ada60823e2d21 Mon Sep 17 00:00:00 2001 +From f34913af5afdc387e79d79d3f10ae65c4c0fde1f Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb98..e03a1d8cd 100644 -- 2.52.0 -From e39fb77521f13219b27d0e39e2a77a84b17ded58 Mon Sep 17 00:00:00 2001 +From 5e74b93b87352d1fc8ba38f76aca030f32a3ead1 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 7204d87a40..4d2052f98e 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From d3d85f0c39e70ea972456bad4c7447b5eb207db3 Mon Sep 17 00:00:00 2001 +From db7f975d923852f9d93d032b52a588925504c5d0 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95..8914a922b 100644 -- 2.52.0 -From 78dd2102bdfd831dd957e3f4c8710eb6ded17f2b Mon Sep 17 00:00:00 2001 +From 6d51695d00d982bae907489634463512df354442 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 9c6f909593..95c6ac5e55 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 6767aeecda4156c7d5e82f3910ff7b23ec59b318 Mon Sep 17 00:00:00 2001 +From c2d11cf6dde6a9bef309a899c1749026106a7918 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index 29b2bc0c91..84dac845ce 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 56bdbcbcabe6116da57bcd583a2101f68815fabd Mon Sep 17 00:00:00 2001 +From c55655d0f695e5d55b239299ab8fc9d4f759393b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000..a171ea656 -- 2.52.0 -From 5d71ba3d69436b26d4940d73f9a55eda46394b15 Mon Sep 17 00:00:00 2001 +From 63ec93c9a203b844e2ede74e74abb181c7c3dbe6 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 diff --git a/patches/6.18/0017-powercap.patch b/patches/6.18/0017-powercap.patch index 207ee9e545..fcb61280e5 100644 --- a/patches/6.18/0017-powercap.patch +++ b/patches/6.18/0017-powercap.patch @@ -1,4 +1,4 @@ -From 6186a782293d3eaa335d0e32048d2b1dd32d4369 Mon Sep 17 00:00:00 2001 +From cf0ba7bf5d6a7feb9851facf1808985a2ed5b89b Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Wed, 14 Jan 2026 20:31:38 -0500 Subject: [PATCH] powercap: intel_rapl: Add PL4 support for Ice Lake From 42a79a4a572407708e73adb0329ad80349a32eb8 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sat, 7 Feb 2026 09:22:15 +0000 Subject: [PATCH 197/236] patches/v6.18: Update to v6.18.9 Generated 17 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.9 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 4 ++-- patches/6.18/0002-surface3.patch | 4 ++-- patches/6.18/0003-mwifiex.patch | 6 +++--- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 6 +++--- patches/6.18/0006-ithc.patch | 4 ++-- patches/6.18/0007-surface-sam.patch | 4 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 4 ++-- patches/6.18/0009-surface-button.patch | 4 ++-- patches/6.18/0010-surface-typecover.patch | 6 +++--- patches/6.18/0011-surface-shutdown.patch | 4 ++-- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 20 ++++++++++---------- patches/6.18/0014-amd-gpio.patch | 4 ++-- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 4 ++-- patches/6.18/0017-powercap.patch | 2 +- 17 files changed, 41 insertions(+), 41 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index e486187ba9..8003e00f07 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 000648f4f90818dc20b4bebfcddc3a9f3803ff15 Mon Sep 17 00:00:00 2001 +From bd4c46d5fcf52346c10baa2f93a8191b3666a7ca Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2..25848f886 100644 -- 2.52.0 -From e041d8263d093f2d2d5123d246e220c53e6ca57b Mon Sep 17 00:00:00 2001 +From 19cebf117e481f0227d7122812b03591199828d1 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index b7faaf7ad9..ff49ca4c94 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From e9e6b39423574dbf8c69dceb448a7d025c76a9d7 Mon Sep 17 00:00:00 2001 +From 69a85d6855669be7e986acef07ccbf8f8bf80448 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0..0b930c91b 100644 -- 2.52.0 -From 4a07615e2ebf577c6e71b51b7badbbba4d633981 Mon Sep 17 00:00:00 2001 +From 3d30bbd21b86edc7aee7f04d63f48274d2b18c91 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 30e46b5e37..9ce3eba23d 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 7e1bb52229f6ce7a4a8b3feeee858c6ccf9eaa79 Mon Sep 17 00:00:00 2001 +From 9593c516ab9ffbaf6f3579fa9b4847334a06bedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From 9c0afb16977536994d235fa7a67344e79f9f56d5 Mon Sep 17 00:00:00 2001 +From 9cfa9e79bfab86b0dd006db23b8f4578d3793f79 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 3767d1a91caf6f15f562b9d1742d0e4ac30ab18f Mon Sep 17 00:00:00 2001 +From 8f1c63004d0669c9026ebf2c888a7aec4ee9956f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index 0006a259d5..f46f25f17a 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From c063b83e99378d0f2f2820291ac0d96f196e080c Mon Sep 17 00:00:00 2001 +From 6f78fa89621ae0d37150a56393c837610d4b64de Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index db12aea6fb..acd5d5440a 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 8b7cb164383dc09f88305bfbe2828edc5ca8456e Mon Sep 17 00:00:00 2001 +From 52589066af6dc055659cc7c36fcafb8dd221d00e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e56955..c19dfba54 100644 -- 2.52.0 -From 7c3015468063bb7a0aa8b51c49290ed1542bd89c Mon Sep 17 00:00:00 2001 +From 4d6c4cb07f0486c014733f8f1641cc4c4cb79c6b Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e236c7ec2..9e31a5fe1 100644 -- 2.52.0 -From bdf9e4ac66246e18f06cae402728aef34e612c33 Mon Sep 17 00:00:00 2001 +From 947c00f6f25ef885ff9cfeee85f449311d822d1a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index fa98034dc7..81e4233e82 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From 329dbd98a2f7dcab6ebce425af6c708319aa352d Mon Sep 17 00:00:00 2001 +From 35c9b0f076fc055736ab686e2e6b9f4ec73e1439 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9..c78806d35 100644 -- 2.52.0 -From b8585c954e2f495be9ed798528f348ab3fda65d2 Mon Sep 17 00:00:00 2001 +From f1739d1bb079de11599ed4e58cba329c585c8bf5 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index 4b7e4bc395..7c58972b3a 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 878de2f4b354ad17071c51b43a4c9b873a5c52dd Mon Sep 17 00:00:00 2001 +From b5dca285f0fa20a64793c71c541a517a01a53ecf Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000..f6c17c4e9 -- 2.52.0 -From 6e8dc33ef616c446653e9b362e3d73b130729190 Mon Sep 17 00:00:00 2001 +From a06532897c1ea9225e069d750bcdc2959a160f76 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 4ec1b82967..91e29f4ce6 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From a2b8be244e3bca9055d360ebc90471d7418c52ab Mon Sep 17 00:00:00 2001 +From 6579116fd37c78498cdd8ec2761dc0253a7cc85c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a2..070c36637 100644 -- 2.52.0 -From 96d18f6989c750179269ae199f4a1f32aa3c3059 Mon Sep 17 00:00:00 2001 +From d12c96869aab1623728e86b5d8f46e92ac2d0234 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 4de12498da..8bcd3f5ac2 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 9bea2a09219c5b3acf4c7ba8b328b1675e964bb7 Mon Sep 17 00:00:00 2001 +From 0e6feff1f9a8b53c04ec9e8d3efb90688b9c047f Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c..43b5d5638 100644 -- 2.52.0 -From 37a68e90e88ad5f17b65dd6e74b91907b9f3d658 Mon Sep 17 00:00:00 2001 +From 06dfa01586a862d15cbb633c909cf03c8e6db0b9 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index 423b78c5c6..d606c61115 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 5f0114d0663f471a37224f81d9decbb4671e5664 Mon Sep 17 00:00:00 2001 +From adbc1603b9afc63dcf78efc80a9ce74e54679f21 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c4d85089d..3d0d35c72 100644 -- 2.52.0 -From e69f8b3a80a4684de31ea21f23211ed2acaeed35 Mon Sep 17 00:00:00 2001 +From 2a2cd81bef4cf21419fc6bccb252b252ece03ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 179dc316b..7d644e1c4 100644 -- 2.52.0 -From e01885e989e3f0f4d8ccef483ae6f7b0896d1cbb Mon Sep 17 00:00:00 2001 +From 9431420d43fa3cc1e95e4f817b401ebb8da97793 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index 4c4acb7df9..dfdd5d394c 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 22ea5007c2f6c4a45778e5719fe68f98f6a128b5 Mon Sep 17 00:00:00 2001 +From 61db0e44597c45b85a384a87294bec26f52c35d9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index bf97d49c2..90eead93d 100644 -- 2.52.0 -From 5f5fe5c30fed707408e995b5f9b4fd70850502ed Mon Sep 17 00:00:00 2001 +From 13dd4da628d723d312830f7174e5dc8fa6f6385b Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index 98d6c15ab6..a4b0e5a39b 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 544ebf521bb51bc76bbb53be59dd343553238299 Mon Sep 17 00:00:00 2001 +From 3f2c59f5654154a80b1fb978c8fa0b5a52c707b4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index 90be19c993..d7c2db1c2e 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From 4efcc8606f380b191a190c0dea444783a76b8e80 Mon Sep 17 00:00:00 2001 +From 543b05525228ed555a763c4207e11f6c9355f32b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2..a6bad2679 100644 -- 2.52.0 -From 9c8c596646650ffc4e2aec66b64bfc53bd1064d6 Mon Sep 17 00:00:00 2001 +From a99581089b3d1df6d9982973b2d2c2fc30530024 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 9e31a5fe1..bdd32551c 100644 -- 2.52.0 -From fdf85e34e0cd9707edead5c6629af8297bfe799e Mon Sep 17 00:00:00 2001 +From dca54560755ceecbed780d61e7935f4f9b73b01f Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 013340569..9e0763bdc 100644 -- 2.52.0 -From f504b621cd3f73e83fa62117d4bef7c623d16859 Mon Sep 17 00:00:00 2001 +From df08cd915853c25601d57c3eba20de1fc66142fd Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0..28b192c9a 100644 -- 2.52.0 -From 9389eecd77c1bd3c64a65e53d51bd872bd08b48a Mon Sep 17 00:00:00 2001 +From 388ea20ca3dc1d2341689908e685a892aa3ddc68 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42..f11b499e1 100644 -- 2.52.0 -From b2ba431af4ef8243a28baef5f221a94343b8ea01 Mon Sep 17 00:00:00 2001 +From 8b8cb7995f3524b791b99d73c0c07d7985db13e1 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc..0976b2679 100644 -- 2.52.0 -From 3a7716a4105e214a32ea0f1d2b41bbdecedc6f7f Mon Sep 17 00:00:00 2001 +From e8b69207500fc57cd884611791e7bd902be0d6a3 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From 9a52132b23e671cc90c43857e933395f8bec3387 Mon Sep 17 00:00:00 2001 +From 78df6291c8680c90b325e3d3936614ed766b537a Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From f34913af5afdc387e79d79d3f10ae65c4c0fde1f Mon Sep 17 00:00:00 2001 +From 13f44051bfd17396abc876b53c732e15951160a2 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb98..e03a1d8cd 100644 -- 2.52.0 -From 5e74b93b87352d1fc8ba38f76aca030f32a3ead1 Mon Sep 17 00:00:00 2001 +From 228f2989668592d6fd7dbaf9afcb45a621f06489 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 4d2052f98e..bdaeb038c9 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From db7f975d923852f9d93d032b52a588925504c5d0 Mon Sep 17 00:00:00 2001 +From 7de9c326ae3b13ac1c7d2fa69da742786e938acb Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95..8914a922b 100644 -- 2.52.0 -From 6d51695d00d982bae907489634463512df354442 Mon Sep 17 00:00:00 2001 +From c4785acab63b4f29bbbaf171d7bfd52aa21a2e40 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 95c6ac5e55..e68f87f345 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From c2d11cf6dde6a9bef309a899c1749026106a7918 Mon Sep 17 00:00:00 2001 +From 4f883a2192301f67ce808158aba2af39522c00ae Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index 84dac845ce..6d233d9b80 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From c55655d0f695e5d55b239299ab8fc9d4f759393b Mon Sep 17 00:00:00 2001 +From f201c243ea7f7a34d3c0743168b51b4cfa45d388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000..a171ea656 -- 2.52.0 -From 63ec93c9a203b844e2ede74e74abb181c7c3dbe6 Mon Sep 17 00:00:00 2001 +From ed2a9266036762ab98a801ee5bd0cb04442d4618 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 diff --git a/patches/6.18/0017-powercap.patch b/patches/6.18/0017-powercap.patch index fcb61280e5..27c77fd511 100644 --- a/patches/6.18/0017-powercap.patch +++ b/patches/6.18/0017-powercap.patch @@ -1,4 +1,4 @@ -From cf0ba7bf5d6a7feb9851facf1808985a2ed5b89b Mon Sep 17 00:00:00 2001 +From 465b1c71a2c4bad54e9b84e02de93322df88d202 Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Wed, 14 Jan 2026 20:31:38 -0500 Subject: [PATCH] powercap: intel_rapl: Add PL4 support for Ice Lake From 434172c82ceaee4d72f821c9bd2374a17d46ca7e Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sat, 7 Feb 2026 09:10:49 +0000 Subject: [PATCH 198/236] patches/v6.12: Update to v6.12.69 Generated 14 patches from linux-surface/kernel branch v6.12-surface Base version: v6.12.69 Branch: v6.12-surface Automatically generated patches using git-format-patchsets. --- patches/6.12/0001-secureboot.patch | 4 ++-- patches/6.12/0002-surface3-oemb.patch | 2 +- patches/6.12/0003-mwifiex.patch | 6 +++--- patches/6.12/0004-ath10k.patch | 2 +- patches/6.12/0005-ipts.patch | 6 +++--- patches/6.12/0006-ithc.patch | 4 ++-- patches/6.12/0007-surface-sam-over-hid.patch | 4 ++-- patches/6.12/0008-surface-button.patch | 4 ++-- patches/6.12/0009-surface-typecover.patch | 6 +++--- patches/6.12/0010-surface-shutdown.patch | 2 +- patches/6.12/0011-surface-gpe.patch | 2 +- patches/6.12/0012-cameras.patch | 20 ++++++++++---------- patches/6.12/0013-amd-gpio.patch | 4 ++-- patches/6.12/0014-rtc.patch | 2 +- 14 files changed, 34 insertions(+), 34 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index 171f300330..142e399708 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 83fb412e5ce1df11aae62b316282cdf3cab99301 Mon Sep 17 00:00:00 2001 +From 6877febf6457275aa81ef3b912bc3393698ce3f3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index b5c79f433..a1bbedd98 100644 -- 2.52.0 -From fe63d5758097d8f030140b054ac6644107c956b9 Mon Sep 17 00:00:00 2001 +From b3b97c7e967ba187f7e19ba2dc601f6adf7bb7ce Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index 5cfaf178b2..a92bba8099 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 8d20e56573c6b88f5e9d26c9b48194a69b1b263d Mon Sep 17 00:00:00 2001 +From 432544da5814c6ef03cea6fd19e304a732c638f9 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index 4f90bcba1f..ec284d30df 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 455aa655eca2c1531e9e719dffe3b8a74b4cdcdd Mon Sep 17 00:00:00 2001 +From 92c40c9dc2adc649202903a880a4376ba421a865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From 4004203431ddaaee61dd98e07b6df4518e4c70f8 Mon Sep 17 00:00:00 2001 +From 426a0dace73b66616780d6cabe2fd4d3e097f0d2 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 8b32ce1c516120ff04578d2984c0a41b6b2eb32b Mon Sep 17 00:00:00 2001 +From 51e1c076bba9fcbff159ca77ba1a82fbf7033ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index 3889fa33f7..dcfc8b554a 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 1272e0f2951f6d2deff64aaea6bcb9c1f1ec5fa5 Mon Sep 17 00:00:00 2001 +From 8c3eb2772c31f18f4d3b9df993fc2984604f9035 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index 2554d07772..e1f9ec697a 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From 18382716c95dcbb8aef8394c695ed7302b237b52 Mon Sep 17 00:00:00 2001 +From 1890f0507b799548781b7a28886b8625399691c0 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 1e4edf896..61d1a8816 100644 -- 2.52.0 -From 02c872988f7201479070a3f10b4518161556368a Mon Sep 17 00:00:00 2001 +From 7f8a88610707324d4109f07afe9279a79c651158 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index c799cc67d..65adfc813 100644 -- 2.52.0 -From 1880d8e4133705698ca7aa18f5b65c7c92ba2de9 Mon Sep 17 00:00:00 2001 +From 4fc39217748aa357920ef5c82932541bb24f7a6a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index 729014279f..a4bae0fb6d 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From 89f46673f771eb27289638133bd55c70dfc953d6 Mon Sep 17 00:00:00 2001 +From bc6959f413d60e79c333fb8b24dd3d35558316e0 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 066e4cd6e..7b320d09d 100644 -- 2.52.0 -From 3e42ef9a26315313a2dc7722645e45d3f2e86646 Mon Sep 17 00:00:00 2001 +From 9e031dc46bd980b02718fd00b1a0a5b9af18f173 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index 973b965457..e0a402df7a 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 9a901fb49e8eeaaf6e32e33d2fb1595a5b68391d Mon Sep 17 00:00:00 2001 +From 2706f5bc42ccf89b99e29d9e6ccce296d577b20b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index f43067f67..1761ca30e 100644 -- 2.52.0 -From 910bd8dce5db8f99e7cc20f5a773ccc14092de00 Mon Sep 17 00:00:00 2001 +From 014f329f675c21a32cf6f9639eed27230380422a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index 8362fafb34..129e728182 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From 833e3db5906a61edde1c514283c500873286192a Mon Sep 17 00:00:00 2001 +From a34c0a35f3e02e016a0f9025f0074b5073ed7acd Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index 5c5d407fe..4e1bfe90e 100644 -- 2.52.0 -From 8821ccb1052dbc6af294c56742662455cd7686ca Mon Sep 17 00:00:00 2001 +From f5ceefaf29e53be0086ecf4820e2a1719b77275a Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index d3d0f2d833..a3165a9546 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From b672d83af9647f51ff73a8158d626898a46e8ec7 Mon Sep 17 00:00:00 2001 +From 42a180489bac8661318ad604eea360b786cebae3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 323a949bb..abc2cdecd 100644 -- 2.52.0 -From f91864077f6380de6d73fea2b935cfe8d0ec0c1d Mon Sep 17 00:00:00 2001 +From 107614f6918d76f712db23504912511c441f517d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index 0e4cb0e66..26b551523 100644 -- 2.52.0 -From 9a1db7e264b5484d7281b8b8f352222e77017acb Mon Sep 17 00:00:00 2001 +From 41bb83b6c2ce88d10aa76f6e233e30beca605db0 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index 379910ea96..c9e75ced02 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 50751f30b80fdf8da3931ea45bff613e9fff20e1 Mon Sep 17 00:00:00 2001 +From 6f15b3e9b2948b4e5c8fd3a22915d813432c1378 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index 460f005b6b..8e7fad88ce 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From 0d638821f83be823bc8345da67dc575b4f63a8a4 Mon Sep 17 00:00:00 2001 +From 790fb8b5cf76dc803866536a02da951aed484c52 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index a8934ddf1a..828722b98d 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From 7425a395008ba82583190496b0d5b931650273de Mon Sep 17 00:00:00 2001 +From ee0d663e7b026f0d55bbaec01a5396dc854564b9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ba98763ce..6021907ec 100644 -- 2.52.0 -From da323c3272093ad7d5d24ec67ff5e255389ea829 Mon Sep 17 00:00:00 2001 +From 2447fb5d79ac300dbb8a9d77c7345b4d480783fc Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 65adfc813..3dcabd6c5 100644 -- 2.52.0 -From b30bb045b4d67722312ba305f9303b8cf2dcbf74 Mon Sep 17 00:00:00 2001 +From df89ea0106e2dc9612841d751af1790dc7590f95 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 81ac4c691..f453c9043 100644 -- 2.52.0 -From e1cef1af2572cb49bc479c781ea313e63a5f1dc6 Mon Sep 17 00:00:00 2001 +From 5d26b73e9c4fafc85e10fa0f6cff5b521439daf9 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -277,7 +277,7 @@ index 9e69ac9cf..d6003198a 100644 -- 2.52.0 -From 299c771ba77c2eddf8704a86e7bab43d83d58d13 Mon Sep 17 00:00:00 2001 +From 382fa1814a74f86e6fdb7cf1958819a47db75e55 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -316,7 +316,7 @@ index 3226888d7..3bfe45b76 100644 -- 2.52.0 -From 30c528c9306fc89ccc0b9494de692ee2eb547f8e Mon Sep 17 00:00:00 2001 +From 3766a8f87d398ee3963d43faca14f695c1736171 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -367,7 +367,7 @@ index f19c8adf2..923ed1b5a 100644 -- 2.52.0 -From 5d50a766308660d2ae03100f2d63689825cc39d2 Mon Sep 17 00:00:00 2001 +From bbdda831930f5248735ac63df2696f2caf286e2a Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -408,7 +408,7 @@ index f453c9043..b8ad6b413 100644 -- 2.52.0 -From 7591d1c40fb71d4b8a7246d9fcc035f6339b82d5 Mon Sep 17 00:00:00 2001 +From 6e50522329564b39a2a263aae50eb61a279d299c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -449,7 +449,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From 1f4c6b08455a323956c12a9c69fb809e0c1e4a92 Mon Sep 17 00:00:00 2001 +From bd12a50a8fa84acc18af0cf1dfa0aa465947b855 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -700,7 +700,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From c44aa32a7a57e44fb992dcdfa30dd2d5723e15ec Mon Sep 17 00:00:00 2001 +From 483a9864ec356caec47b62251a5289962cbc189b Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index 1b2c0c8fde..40b66c0941 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From 949bb8d4c19b6f83e581980373f0cc6d17a1985f Mon Sep 17 00:00:00 2001 +From 9993bf7a1efe55b66f8c8109e65e0ac355f1ba25 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 63adda8a1..00914222a 100644 -- 2.52.0 -From 07eb4f50c84102985c37e930e6596bffe93ece1d Mon Sep 17 00:00:00 2001 +From 1494323ffcfaadbb7c19554d347dd0cf270134de Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index e857688e45..bdf7409226 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From d7276bb3fd747ae88c0638c294e9f3e8ab60d6cd Mon Sep 17 00:00:00 2001 +From e99383a91ae6cd8861bfdc564ed1d02d23263bec Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From faedd344762f9db3fe3c79e4f085d4ca7891e0c8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 7 Feb 2026 15:32:30 +0100 Subject: [PATCH 199/236] Update Debian kernel to v6.18.8 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 7f000371e3..1a734eb33c 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.18.7" +KERNEL_VERSION="6.18.8" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 7ce698216b4ed2ff9c62f1211b495d2cde1cc782 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 7 Feb 2026 15:33:10 +0100 Subject: [PATCH 200/236] Update Arch kernel to v6.18.8 --- pkg/arch/kernel/PKGBUILD | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index e783a3bc3e..6c38da6194 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.18.7.arch1 +pkgver=6.18.8.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -65,27 +65,27 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('4323793a7e149c18632671b692d1f90ec991c2097167d9de8413636ae432073c' +sha256sums=('e3cc223b5d7b1cd25ed671e24c072d6350494a1c3dbf1626d957c923ff3ec959' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '504062f0ed5f4bd238ff1775ba809ce2d10e675902532c1a0796bc3f2a5b47aa' - '0ec23c28f5ada5df2872806efcc2ef5b1ec225891112c9eb8dd2b0b6b507c923' - '5cba99600cea14ae8b8e512e79e14897b47a668c469a942752b36bb3bfa1f43a' - '82062e65aa29d7a5900ce9096e94a670da9eeac405b7bcfe8ff7a299147d044a' - '914d2dc9724c7e9f50948680db4291646d9ebf97ee8f94c819c77fd5a15a6bf9' - 'baa00e12c12e10f86857857977183a4c144a2f6100be9aab85de436510010a8b' - '0243436e97a99881b8e8974fe0cfce14b0d80e5ad9be82c527e9616412a494ce' - '6dd0dda89c4f76a6ba51e2b5107f0d70866ffadea0918ebca5f4a4ed57f7eb21' - 'd9beeb6b18cafca90445adb0897d6033684060852ca45634595707e62898ba75' - '085f08e1fe5c505f6a8e95819e69e3144ace6954260131c9d0910beac1176733' - '96f3c35d2a763346d02ce212747e4944dc45bfb2e91b6c61fe8e4d60a0634c95' - '7e50bb11c051579042a172f7563bc1c0d33cc7a649334ec1f428641e10b0c4a5' - 'd8427605a6805152517d7edc14c06dd86f8b004d6cfe11ea33177938c5720a7c' - 'c34120274bacbd5e0e7c7a0f8db420bf5da0773e05752e1510324469d48f4f53' - 'ba6be94290bcfcd6614fefad4b9418f812699a7a340a4edd218628324c2d2c9d' - 'fde839050a7648ff1b8782df364e1e62f6a2b575e437e04043c7179d74cbf157' - 'c9350beb089cb23b22ff156521575979d23abaafc3adc69d5068ebc303cfa0fe') + '25457105444c91e4de57c6938f4e36f98e2ce1d6f079b401ae8d6c2ada689c06' + 'a813b8fda4a4eadd13ad78fac982aba0abcad72398cd9989eaafcc8372d3d39b' + 'a421e02dcbad81ec20e7c0e9c83a26ea018b203d0da96090cce25f8da6c63982' + 'e3022dbf12cf2e24fe0be1777da129808d9827be89e09d34f4971c5bfda53972' + '4b2972e73d311ac9f603e9229491464439a36537666f426797dcc70ecc611a4b' + '7b908157f3c88a16106555513d36c00a20ceec78314600b9ad042c8e62a7a90a' + '33347c5a7c7112ad08d83dbb54d0841c1044c62c9695a40a3cf09a54a65c4684' + 'c77726fee303a204f05385cacd6644a3e3452580056391d11873919b18ca5efb' + 'e40a928da09249e35f40072bee54f61a0b5d9aea12917674fa9c4a3944072e2b' + 'b6badd94dc5157c88ed64d34a38a4333d0cc6b19190d179a57a5a2fb3248bc24' + '3722b78f24f19d653849864fc2ae24c782a2c83519620551191b96bcaac1a3cb' + 'aa9601d0e3e8c5268c3e975632e8de93e001515b25b8c0caf2c0428907783c68' + 'aaabc6fe397ad534e0d1654ffafefe8aebd9b8cbb52d05b0abb0c394e1dce650' + 'beff0cf807dfbcbe58505f9d101a910679e360a11bb82ce9194db367c844ea7c' + '34ce59aa1f32cdcbb48307cbdc06de27376c909938fb6f8647c3dc47f859aac6' + 'bb2c5d4718eba576037d7d8c59dbd0227cadf5184b644071e26d441b38911e77' + '4e5876d308e391fc2055a6b1671d8af0bb394e81e05bede7edcc829ab6ba3059') export KBUILD_BUILD_HOST=archlinux From 581fbdd6134d8cc8a03011c1cea8f704359fde6a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 7 Feb 2026 15:33:34 +0100 Subject: [PATCH 201/236] Update Fedora kernels to v6.18.8 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index efbee59e49..ed2f4dcc19 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.18.7-0" +PACKAGE_TAG = "kernel-6.18.8-0" ## ## The release number of the modified kernel package. From 0521eeace5132b3ad77bc4ebcdfec084959b58c0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 7 Feb 2026 17:24:02 +0100 Subject: [PATCH 202/236] fixup! Update Arch kernel to v6.18.8 --- pkg/arch/kernel/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 6c38da6194..c192df9ec8 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.18.8.arch1 +pkgver=6.18.8.arch2 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -65,7 +65,7 @@ validpgpkeys=( '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('e3cc223b5d7b1cd25ed671e24c072d6350494a1c3dbf1626d957c923ff3ec959' +sha256sums=('9526800a611ea4a46e8410686c89bab5a92df4b556b853e8933caa0d6cca835a' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' From 829ceccd5970ed3621a30d9fcfb2fe6584a3aab7 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Fri, 20 Feb 2026 09:24:00 +0000 Subject: [PATCH 203/236] patches/v6.18: Update to v6.18.13 Generated 17 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.13 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 4 +- patches/6.18/0002-surface3.patch | 4 +- patches/6.18/0003-mwifiex.patch | 10 ++-- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 6 +-- patches/6.18/0006-ithc.patch | 4 +- patches/6.18/0007-surface-sam.patch | 4 +- patches/6.18/0008-surface-sam-over-hid.patch | 4 +- patches/6.18/0009-surface-button.patch | 4 +- patches/6.18/0010-surface-typecover.patch | 48 ++++++++++---------- patches/6.18/0011-surface-shutdown.patch | 4 +- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 20 ++++---- patches/6.18/0014-amd-gpio.patch | 4 +- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 12 ++--- patches/6.18/0017-powercap.patch | 2 +- 17 files changed, 68 insertions(+), 68 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 8003e00f07..e31e227c4d 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From bd4c46d5fcf52346c10baa2f93a8191b3666a7ca Mon Sep 17 00:00:00 2001 +From 4b4ce7116b7c0ad7d1e51ad619b9eb81d66af13b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2..25848f886 100644 -- 2.52.0 -From 19cebf117e481f0227d7122812b03591199828d1 Mon Sep 17 00:00:00 2001 +From a60e892a264dac56d17c0eef4af8b6248c271444 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index ff49ca4c94..e939c9b210 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 69a85d6855669be7e986acef07ccbf8f8bf80448 Mon Sep 17 00:00:00 2001 +From 5e759ec36f6a4329bda2f6fc1d13390a1b6b7074 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0..0b930c91b 100644 -- 2.52.0 -From 3d30bbd21b86edc7aee7f04d63f48274d2b18c91 Mon Sep 17 00:00:00 2001 +From 4a41660055f580887775fda819a09aae4e7fa4bb Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 9ce3eba23d..1b5fe41fb1 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 9593c516ab9ffbaf6f3579fa9b4847334a06bedb Mon Sep 17 00:00:00 2001 +From b6b1c95e100682c8674b3db7155f8bc60a453171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From 9cfa9e79bfab86b0dd006db23b8f4578d3793f79 Mon Sep 17 00:00:00 2001 +From 6c0913443c9ba701b349a05f4f1672b1278b8f8b Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 8f1c63004d0669c9026ebf2c888a7aec4ee9956f Mon Sep 17 00:00:00 2001 +From 72d0eb8d4a676652ec58e7e707e5f4cd6d51b30d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 3420f711f..50362656f 100644 +index a953fa9af..7e4670599 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 3420f711f..50362656f 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4192,6 +4194,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4194,6 +4196,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index f46f25f17a..e749fc75b4 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 6f78fa89621ae0d37150a56393c837610d4b64de Mon Sep 17 00:00:00 2001 +From 7d52f30be7f191a3f4206e6cb43b43c66b3b30df Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index acd5d5440a..71440801e0 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 52589066af6dc055659cc7c36fcafb8dd221d00e Mon Sep 17 00:00:00 2001 +From 0c42d3ef5be780bec2767ad0910ab96200ad50f8 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e56955..c19dfba54 100644 -- 2.52.0 -From 4d6c4cb07f0486c014733f8f1641cc4c4cb79c6b Mon Sep 17 00:00:00 2001 +From 0dddf0a24b18680fa269a0d3a7b4c87597fc2535 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index e236c7ec2..9e31a5fe1 100644 -- 2.52.0 -From 947c00f6f25ef885ff9cfeee85f449311d822d1a Mon Sep 17 00:00:00 2001 +From 2d3ebe8da80b712d62f6556bd35bfec0cbd8855b Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index 81e4233e82..90ef4fc94f 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From 35c9b0f076fc055736ab686e2e6b9f4ec73e1439 Mon Sep 17 00:00:00 2001 +From d52e2510add1b174d32ac5476fbee0138f642261 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9..c78806d35 100644 -- 2.52.0 -From f1739d1bb079de11599ed4e58cba329c585c8bf5 Mon Sep 17 00:00:00 2001 +From bcae5998d9e659722f1c1912690efbe11afc13f9 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index 7c58972b3a..f89d814fe8 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From b5dca285f0fa20a64793c71c541a517a01a53ecf Mon Sep 17 00:00:00 2001 +From d64b237185aec90aab4278469a5a826348065b3f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000..f6c17c4e9 -- 2.52.0 -From a06532897c1ea9225e069d750bcdc2959a160f76 Mon Sep 17 00:00:00 2001 +From 9a5f80d5b74c3ff8d31f2b22e37bcc4792d91a23 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 91e29f4ce6..d844488d6c 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 6579116fd37c78498cdd8ec2761dc0253a7cc85c Mon Sep 17 00:00:00 2001 +From aea01d05f5e71da926fbac44c158ce1d7fe98562 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a2..070c36637 100644 -- 2.52.0 -From d12c96869aab1623728e86b5d8f46e92ac2d0234 Mon Sep 17 00:00:00 2001 +From 08a08c034bbc0f8d4c11ff60c7d078c6de5542af Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 8bcd3f5ac2..9daa7778bb 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 0e6feff1f9a8b53c04ec9e8d3efb90688b9c047f Mon Sep 17 00:00:00 2001 +From cad7c632ef22427f26dceb4e1a3b0d5d143991d8 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c..43b5d5638 100644 -- 2.52.0 -From 06dfa01586a862d15cbb633c909cf03c8e6db0b9 Mon Sep 17 00:00:00 2001 +From f1c04affde903b94f8cd1e37c48a6a92dc280443 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index d606c61115..afc3149225 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From adbc1603b9afc63dcf78efc80a9ce74e54679f21 Mon Sep 17 00:00:00 2001 +From 7480aa8ac22d073ca9e6d56305bcf7eb578955e9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c4d85089d..3d0d35c72 100644 -- 2.52.0 -From 2a2cd81bef4cf21419fc6bccb252b252ece03ac4 Mon Sep 17 00:00:00 2001 +From 09d6209e5e3de8e20d764975e783a155ede483ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 179dc316b..7d644e1c4 100644 +index a0c1ad5ac..2cd18fe61 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -130,7 +130,7 @@ index 179dc316b..7d644e1c4 100644 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -425,6 +435,16 @@ static const struct mt_class mt_classes[] = { +@@ -426,6 +436,16 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, }, @@ -147,7 +147,7 @@ index 179dc316b..7d644e1c4 100644 { } }; -@@ -1842,6 +1862,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1843,6 +1863,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index 179dc316b..7d644e1c4 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1870,6 +1953,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1871,6 +1954,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index 179dc316b..7d644e1c4 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1908,8 +1994,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1909,8 +1995,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index 179dc316b..7d644e1c4 100644 if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && !hid_find_field(hdev, HID_INPUT_REPORT, -@@ -1923,8 +2011,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1924,8 +2012,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index 179dc316b..7d644e1c4 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1985,6 +2075,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1986,6 +2076,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index 179dc316b..7d644e1c4 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2429,6 +2520,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2430,6 +2521,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, @@ -274,7 +274,7 @@ index 179dc316b..7d644e1c4 100644 -- 2.52.0 -From 9431420d43fa3cc1e95e4f817b401ebb8da97793 Mon Sep 17 00:00:00 2001 +From 9a451e7c0c26329ad8e334238c601cc2e1c4cf0a Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 7d644e1c4..0eb4f7d12 100644 +index 2cd18fe61..c4179f6c3 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -81,6 +81,7 @@ MODULE_LICENSE("GPL"); @@ -323,7 +323,7 @@ index 7d644e1c4..0eb4f7d12 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -437,6 +440,7 @@ static const struct mt_class mt_classes[] = { +@@ -438,6 +441,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -331,7 +331,7 @@ index 7d644e1c4..0eb4f7d12 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1463,6 +1467,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1464,6 +1468,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -341,7 +341,7 @@ index 7d644e1c4..0eb4f7d12 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1490,6 +1497,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1491,6 +1498,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -363,7 +363,7 @@ index 7d644e1c4..0eb4f7d12 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1516,6 +1538,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1517,6 +1539,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -371,7 +371,7 @@ index 7d644e1c4..0eb4f7d12 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1523,6 +1546,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1524,6 +1547,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -391,7 +391,7 @@ index 7d644e1c4..0eb4f7d12 100644 /* let hid-core decide for the others */ return 0; } -@@ -1532,11 +1568,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1533,11 +1569,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -413,7 +413,7 @@ index 7d644e1c4..0eb4f7d12 100644 return 0; } -@@ -1719,6 +1765,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1720,6 +1766,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index 7d644e1c4..0eb4f7d12 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1776,6 +1858,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1777,6 +1859,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 7d644e1c4..0eb4f7d12 100644 default: suffix = "UNKNOWN"; break; -@@ -1862,30 +1951,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1863,30 +1952,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 7d644e1c4..0eb4f7d12 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1894,8 +1959,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1895,8 +1960,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 7d644e1c4..0eb4f7d12 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -2053,13 +2119,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -2054,13 +2120,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 7d644e1c4..0eb4f7d12 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -2068,12 +2145,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -2069,12 +2146,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index dfdd5d394c..b4c609ada6 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 61db0e44597c45b85a384a87294bec26f52c35d9 Mon Sep 17 00:00:00 2001 +From f6f5d63846d4b868464b914ec63baf2ef000d95a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index bf97d49c2..90eead93d 100644 -- 2.52.0 -From 13dd4da628d723d312830f7174e5dc8fa6f6385b Mon Sep 17 00:00:00 2001 +From e37ed31e23703d9f2f210e26677d41ef3dde634b Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index a4b0e5a39b..e96101ebb4 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 3f2c59f5654154a80b1fb978c8fa0b5a52c707b4 Mon Sep 17 00:00:00 2001 +From fe14472400b7156fb3fdb8fc9108018da180da32 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index d7c2db1c2e..4cd22fd07c 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From 543b05525228ed555a763c4207e11f6c9355f32b Mon Sep 17 00:00:00 2001 +From 79d2acffafb8f9dfd0615feaf3681ad6f544654b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2..a6bad2679 100644 -- 2.52.0 -From a99581089b3d1df6d9982973b2d2c2fc30530024 Mon Sep 17 00:00:00 2001 +From 8d0914e088c9a8303ff59fd76b0efb63fcb66fcb Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 9e31a5fe1..bdd32551c 100644 -- 2.52.0 -From dca54560755ceecbed780d61e7935f4f9b73b01f Mon Sep 17 00:00:00 2001 +From d5b1ddd3cc136ba7710e4781a4bcd08fea0ed6fa Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 013340569..9e0763bdc 100644 -- 2.52.0 -From df08cd915853c25601d57c3eba20de1fc66142fd Mon Sep 17 00:00:00 2001 +From 4d89428772cec0f47fba2a04dd663f21df1d20d6 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0..28b192c9a 100644 -- 2.52.0 -From 388ea20ca3dc1d2341689908e685a892aa3ddc68 Mon Sep 17 00:00:00 2001 +From 12273c1327ac6f6249dc771f125dfb4a93583593 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42..f11b499e1 100644 -- 2.52.0 -From 8b8cb7995f3524b791b99d73c0c07d7985db13e1 Mon Sep 17 00:00:00 2001 +From a1d8907d34da038a7caeeae5258de037db32b48d Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc..0976b2679 100644 -- 2.52.0 -From e8b69207500fc57cd884611791e7bd902be0d6a3 Mon Sep 17 00:00:00 2001 +From 16d8bb8adce156323c6c2d698fbbfc3846a5a760 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From 78df6291c8680c90b325e3d3936614ed766b537a Mon Sep 17 00:00:00 2001 +From 93b8ec92a713fbe3846eee21d24f4b1a53dea456 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From 13f44051bfd17396abc876b53c732e15951160a2 Mon Sep 17 00:00:00 2001 +From f8485df32505cd4f3ab155c0723dac20fc4c6cc4 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb98..e03a1d8cd 100644 -- 2.52.0 -From 228f2989668592d6fd7dbaf9afcb45a621f06489 Mon Sep 17 00:00:00 2001 +From ce276ac4c6169e6194f4af489a6aaa9d91b022fd Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index bdaeb038c9..22572d8aa6 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 7de9c326ae3b13ac1c7d2fa69da742786e938acb Mon Sep 17 00:00:00 2001 +From 69c528d432300afb2d6f516bbeb5387f604f7c1a Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 9fa321a95..8914a922b 100644 -- 2.52.0 -From c4785acab63b4f29bbbaf171d7bfd52aa21a2e40 Mon Sep 17 00:00:00 2001 +From ed986760aea58b450fd5d68a7680e5e89b13b956 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index e68f87f345..f9ecbe14a7 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 4f883a2192301f67ce808158aba2af39522c00ae Mon Sep 17 00:00:00 2001 +From 572c4db540d3260d10f88fe175faa8b095e81d47 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index 6d233d9b80..cd2b73ef15 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From f201c243ea7f7a34d3c0743168b51b4cfa45d388 Mon Sep 17 00:00:00 2001 +From fcc0ca5789466264c908c7a793ee86f7848d3460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000..a171ea656 -- 2.52.0 -From ed2a9266036762ab98a801ee5bd0cb04442d4618 Mon Sep 17 00:00:00 2001 +From 49aefa6d21438030fd0b59bbccaff01540ee679b Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 @@ -168,7 +168,7 @@ Patchset: hid-surface 1 file changed, 30 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 0eb4f7d12..8f2ed29b4 100644 +index c4179f6c3..d59fe2185 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); @@ -187,7 +187,7 @@ index 0eb4f7d12..8f2ed29b4 100644 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -449,6 +451,10 @@ static const struct mt_class mt_classes[] = { +@@ -450,6 +452,10 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_WIN8_PTP_BUTTONS, .export_all_inputs = true }, @@ -198,7 +198,7 @@ index 0eb4f7d12..8f2ed29b4 100644 { } }; -@@ -2180,11 +2186,30 @@ static void mt_remove(struct hid_device *hdev) +@@ -2181,11 +2187,30 @@ static void mt_remove(struct hid_device *hdev) static void mt_on_hid_hw_open(struct hid_device *hdev) { @@ -229,7 +229,7 @@ index 0eb4f7d12..8f2ed29b4 100644 mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); } -@@ -2621,6 +2646,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2622,6 +2647,11 @@ static const struct hid_device_id mt_devices[] = { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_MICROSOFT, 0x09c0) }, diff --git a/patches/6.18/0017-powercap.patch b/patches/6.18/0017-powercap.patch index 27c77fd511..68f5a19ecb 100644 --- a/patches/6.18/0017-powercap.patch +++ b/patches/6.18/0017-powercap.patch @@ -1,4 +1,4 @@ -From 465b1c71a2c4bad54e9b84e02de93322df88d202 Mon Sep 17 00:00:00 2001 +From c142c6d09d7d2d877c7e590d90d9c0aa2b6dd075 Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Wed, 14 Jan 2026 20:31:38 -0500 Subject: [PATCH] powercap: intel_rapl: Add PL4 support for Ice Lake From 221a8092c0ac076e33a8bd77b9d8e5db4b353ec6 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Fri, 20 Feb 2026 09:15:45 +0000 Subject: [PATCH 204/236] patches/v6.12: Update to v6.12.74 Generated 14 patches from linux-surface/kernel branch v6.12-surface Base version: v6.12.74 Branch: v6.12-surface Automatically generated patches using git-format-patchsets. --- patches/6.12/0001-secureboot.patch | 4 +- patches/6.12/0002-surface3-oemb.patch | 2 +- patches/6.12/0003-mwifiex.patch | 10 ++-- patches/6.12/0004-ath10k.patch | 2 +- patches/6.12/0005-ipts.patch | 6 +-- patches/6.12/0006-ithc.patch | 4 +- patches/6.12/0007-surface-sam-over-hid.patch | 4 +- patches/6.12/0008-surface-button.patch | 4 +- patches/6.12/0009-surface-typecover.patch | 48 ++++++++++---------- patches/6.12/0010-surface-shutdown.patch | 2 +- patches/6.12/0011-surface-gpe.patch | 2 +- patches/6.12/0012-cameras.patch | 20 ++++---- patches/6.12/0013-amd-gpio.patch | 4 +- patches/6.12/0014-rtc.patch | 2 +- 14 files changed, 57 insertions(+), 57 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index 142e399708..83d6908e54 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 6877febf6457275aa81ef3b912bc3393698ce3f3 Mon Sep 17 00:00:00 2001 +From 8b1b5cd729869a871db085ccc43295634b09b09b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index b5c79f433..a1bbedd98 100644 -- 2.52.0 -From b3b97c7e967ba187f7e19ba2dc601f6adf7bb7ce Mon Sep 17 00:00:00 2001 +From 8cf83548f5d2bb86f2d715927e42b39583a51153 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index a92bba8099..1577da4b04 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 432544da5814c6ef03cea6fd19e304a732c638f9 Mon Sep 17 00:00:00 2001 +From 9d6c8c98203766acc3fe944da6518fc68183f3b4 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index ec284d30df..fa9e0b231b 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 92c40c9dc2adc649202903a880a4376ba421a865 Mon Sep 17 00:00:00 2001 +From ba20c28fc68867c82de5787c33b729478c4843cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.52.0 -From 426a0dace73b66616780d6cabe2fd4d3e097f0d2 Mon Sep 17 00:00:00 2001 +From 1371b01d866820cc362e5f15fbb411df69fd06a5 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.52.0 -From 51e1c076bba9fcbff159ca77ba1a82fbf7033ecb Mon Sep 17 00:00:00 2001 +From 47c8c0aaf3d54f2d46a2469c0555e9569b2ce131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 603ff13d9..9209e8e29 100644 +index 490efe4d6..e15f99ee3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 603ff13d9..9209e8e29 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4009,6 +4011,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4011,6 +4013,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index dcfc8b554a..3c98f90458 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 8c3eb2772c31f18f4d3b9df993fc2984604f9035 Mon Sep 17 00:00:00 2001 +From abdf26688b6c761b03e6a56d310504e63519544a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index e1f9ec697a..c303faabb1 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From 1890f0507b799548781b7a28886b8625399691c0 Mon Sep 17 00:00:00 2001 +From 41c0348077f9cb3df9ae7109ad3c60afa373347c Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 1e4edf896..61d1a8816 100644 -- 2.52.0 -From 7f8a88610707324d4109f07afe9279a79c651158 Mon Sep 17 00:00:00 2001 +From f3802a79caac1ebbbf4780580982098c3beb38c7 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index c799cc67d..65adfc813 100644 -- 2.52.0 -From 4fc39217748aa357920ef5c82932541bb24f7a6a Mon Sep 17 00:00:00 2001 +From 4e08db916e493aa8197a2d7a29f23d439ece7abf Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index a4bae0fb6d..4453f31966 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From bc6959f413d60e79c333fb8b24dd3d35558316e0 Mon Sep 17 00:00:00 2001 +From 8a87179788582177344e3631f95e620104cb6e90 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 066e4cd6e..7b320d09d 100644 -- 2.52.0 -From 9e031dc46bd980b02718fd00b1a0a5b9af18f173 Mon Sep 17 00:00:00 2001 +From 081ec805c41368484ab34868192862970aa6fc8d Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index e0a402df7a..17d191954c 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 2706f5bc42ccf89b99e29d9e6ccce296d577b20b Mon Sep 17 00:00:00 2001 +From 2f42938beeefa2b8f5773f2fc913c3f13e8a3aef Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index f43067f67..1761ca30e 100644 -- 2.52.0 -From 014f329f675c21a32cf6f9639eed27230380422a Mon Sep 17 00:00:00 2001 +From 7aaf3683c5bd5b4d6648fdf9b62651150b4a7fd0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index 129e728182..fc05e3b7ff 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From a34c0a35f3e02e016a0f9025f0074b5073ed7acd Mon Sep 17 00:00:00 2001 +From 4aa6a238f270308804dd79d4c08821c6f4ef72d3 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index 5c5d407fe..4e1bfe90e 100644 -- 2.52.0 -From f5ceefaf29e53be0086ecf4820e2a1719b77275a Mon Sep 17 00:00:00 2001 +From f24443be9df034a21f1e4ed326c5bb2a5ea71d66 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index a3165a9546..cc4f521a04 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From 42a180489bac8661318ad604eea360b786cebae3 Mon Sep 17 00:00:00 2001 +From f9b45cc859c8379e5f12d738f414292146328bbe Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 323a949bb..abc2cdecd 100644 -- 2.52.0 -From 107614f6918d76f712db23504912511c441f517d Mon Sep 17 00:00:00 2001 +From af01dfc089d8eebc52c1828c885e43749316b54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 0e4cb0e66..26b551523 100644 +index fcfc508d1..be4e0ebbc 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -130,7 +130,7 @@ index 0e4cb0e66..26b551523 100644 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -405,6 +415,16 @@ static const struct mt_class mt_classes[] = { +@@ -406,6 +416,16 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, }, @@ -147,7 +147,7 @@ index 0e4cb0e66..26b551523 100644 { } }; -@@ -1763,6 +1783,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1764,6 +1784,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index 0e4cb0e66..26b551523 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1786,6 +1869,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1787,6 +1870,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index 0e4cb0e66..26b551523 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1824,8 +1910,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1825,8 +1911,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index 0e4cb0e66..26b551523 100644 if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1834,8 +1922,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1835,8 +1923,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index 0e4cb0e66..26b551523 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1885,6 +1975,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1886,6 +1976,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index 0e4cb0e66..26b551523 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2314,6 +2405,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2315,6 +2406,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -274,7 +274,7 @@ index 0e4cb0e66..26b551523 100644 -- 2.52.0 -From 41bb83b6c2ce88d10aa76f6e233e30beca605db0 Mon Sep 17 00:00:00 2001 +From 3874b935193791b6d142f64fb16071a77da3aa3e Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 26b551523..37a3e6489 100644 +index be4e0ebbc..a1df34afc 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -323,7 +323,7 @@ index 26b551523..37a3e6489 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -417,6 +420,7 @@ static const struct mt_class mt_classes[] = { +@@ -418,6 +421,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -331,7 +331,7 @@ index 26b551523..37a3e6489 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1395,6 +1399,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1396,6 +1400,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -341,7 +341,7 @@ index 26b551523..37a3e6489 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1422,6 +1429,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1423,6 +1430,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -363,7 +363,7 @@ index 26b551523..37a3e6489 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1443,6 +1465,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1444,6 +1466,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -371,7 +371,7 @@ index 26b551523..37a3e6489 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1450,6 +1473,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1451,6 +1474,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -391,7 +391,7 @@ index 26b551523..37a3e6489 100644 /* let hid-core decide for the others */ return 0; } -@@ -1459,11 +1495,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1460,11 +1496,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -413,7 +413,7 @@ index 26b551523..37a3e6489 100644 return 0; } -@@ -1648,6 +1694,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1649,6 +1695,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index 26b551523..37a3e6489 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1697,6 +1779,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1698,6 +1780,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 26b551523..37a3e6489 100644 default: suffix = "UNKNOWN"; break; -@@ -1783,30 +1872,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1784,30 +1873,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 26b551523..37a3e6489 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1815,8 +1880,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1816,8 +1881,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 26b551523..37a3e6489 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -1953,13 +2019,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -1954,13 +2020,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 26b551523..37a3e6489 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1968,12 +2045,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -1969,12 +2046,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index c9e75ced02..0619bca16b 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 6f15b3e9b2948b4e5c8fd3a22915d813432c1378 Mon Sep 17 00:00:00 2001 +From f9dad7420d256b7fa2b822db3112eeb32066f704 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index 8e7fad88ce..cc91521d99 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From 790fb8b5cf76dc803866536a02da951aed484c52 Mon Sep 17 00:00:00 2001 +From 35390087776e895b07f81f0af75cb21814b61e9e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index 828722b98d..7c16c8ef71 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From ee0d663e7b026f0d55bbaec01a5396dc854564b9 Mon Sep 17 00:00:00 2001 +From d0296461bb4c7a98b2a8fc0234c841a8c0adea30 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ba98763ce..6021907ec 100644 -- 2.52.0 -From 2447fb5d79ac300dbb8a9d77c7345b4d480783fc Mon Sep 17 00:00:00 2001 +From 759e596605e96b0f66e3cda1cd757386c80fc2f6 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 65adfc813..3dcabd6c5 100644 -- 2.52.0 -From df89ea0106e2dc9612841d751af1790dc7590f95 Mon Sep 17 00:00:00 2001 +From 1f9943aad6051f1db715ee97dadffd4c370c0114 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 81ac4c691..f453c9043 100644 -- 2.52.0 -From 5d26b73e9c4fafc85e10fa0f6cff5b521439daf9 Mon Sep 17 00:00:00 2001 +From f8915a8e39e48cc7812980b2a5e3921c4233e77e Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -277,7 +277,7 @@ index 9e69ac9cf..d6003198a 100644 -- 2.52.0 -From 382fa1814a74f86e6fdb7cf1958819a47db75e55 Mon Sep 17 00:00:00 2001 +From 24fe1fd44f8dce69d810881dd42f02db50ff82d2 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -316,7 +316,7 @@ index 3226888d7..3bfe45b76 100644 -- 2.52.0 -From 3766a8f87d398ee3963d43faca14f695c1736171 Mon Sep 17 00:00:00 2001 +From ff6de3ab3241447e8076cf58462215901a5e625b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -367,7 +367,7 @@ index f19c8adf2..923ed1b5a 100644 -- 2.52.0 -From bbdda831930f5248735ac63df2696f2caf286e2a Mon Sep 17 00:00:00 2001 +From b928afccb5e17b202cfd8a55e960b0360a2dc0f7 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -408,7 +408,7 @@ index f453c9043..b8ad6b413 100644 -- 2.52.0 -From 6e50522329564b39a2a263aae50eb61a279d299c Mon Sep 17 00:00:00 2001 +From 5230e237ca2ebcdcc24e1c43384ce3f76c515aa0 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -449,7 +449,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.52.0 -From bd12a50a8fa84acc18af0cf1dfa0aa465947b855 Mon Sep 17 00:00:00 2001 +From 55d90afcd6b17799059e0a1c7ee7b37276a838ba Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -700,7 +700,7 @@ index 000000000..35aeb5db8 -- 2.52.0 -From 483a9864ec356caec47b62251a5289962cbc189b Mon Sep 17 00:00:00 2001 +From 7040a2341b90a9d6792d2c5f763ed52a37e28318 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index 40b66c0941..2692692304 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From 9993bf7a1efe55b66f8c8109e65e0ac355f1ba25 Mon Sep 17 00:00:00 2001 +From d2977155e31799f8789cbcef4fd860038361c158 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index 63adda8a1..00914222a 100644 -- 2.52.0 -From 1494323ffcfaadbb7c19554d347dd0cf270134de Mon Sep 17 00:00:00 2001 +From 19369b388a100af758315e58bcb8a2f71488ebef Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index bdf7409226..f89f71f413 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From e99383a91ae6cd8861bfdc564ed1d02d23263bec Mon Sep 17 00:00:00 2001 +From 73e1b53a85f74573a273a42358563a9748ee952c Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From b66b96210e27b45006e2bb0d6893c0aa388a3627 Mon Sep 17 00:00:00 2001 From: Cornell Chin Date: Sat, 7 Mar 2026 13:47:19 -0500 Subject: [PATCH 205/236] Update v6.18 patches Changes: - Rebase onto v6.18.16 --- patches/6.18/0001-secureboot.patch | 14 ++-- patches/6.18/0002-surface3.patch | 16 ++-- patches/6.18/0003-mwifiex.patch | 28 +++---- patches/6.18/0004-ath10k.patch | 6 +- patches/6.18/0005-ipts.patch | 84 ++++++++++---------- patches/6.18/0006-ithc.patch | 48 +++++------ patches/6.18/0007-surface-sam.patch | 16 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 16 ++-- patches/6.18/0009-surface-button.patch | 12 +-- patches/6.18/0010-surface-typecover.patch | 84 ++++++++++---------- patches/6.18/0011-surface-shutdown.patch | 24 +++--- patches/6.18/0012-surface-gpe.patch | 6 +- patches/6.18/0013-cameras.patch | 82 +++++++++---------- patches/6.18/0014-amd-gpio.patch | 12 +-- patches/6.18/0015-rtc.patch | 6 +- patches/6.18/0016-hid-surface.patch | 42 +++++----- patches/6.18/0017-powercap.patch | 30 ------- 17 files changed, 248 insertions(+), 278 deletions(-) delete mode 100644 patches/6.18/0017-powercap.patch diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index e31e227c4d..18249af940 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 4b4ce7116b7c0ad7d1e51ad619b9eb81d66af13b Mon Sep 17 00:00:00 2001 +From 1c440464ed3603305d6d9a862597fc17aff88726 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -17,7 +17,7 @@ Patchset: secureboot 1 file changed, 4 insertions(+) diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index 9bea5a1e2..25848f886 100644 +index 9bea5a1e2c52..25848f886ad6 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -111,7 +111,11 @@ extra_header_fields: @@ -33,9 +33,9 @@ index 9bea5a1e2..25848f886 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.52.0 +2.53.0 -From a60e892a264dac56d17c0eef4af8b6248c271444 Mon Sep 17 00:00:00 2001 +From adefb036d5f0a08f88f9e3c06d599ab5fb45fa62 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 6c42061ca..f7cb5669b 100644 +index 6c42061ca20e..f7cb5669b5fb 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3342,6 +3342,11 @@ @@ -69,7 +69,7 @@ index 6c42061ca..f7cb5669b 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 26e45f86b..8ec46d456 100644 +index 26e45f86b955..8ec46d4565a0 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -38,6 +38,7 @@ @@ -108,5 +108,5 @@ index 26e45f86b..8ec46d456 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index e939c9b210..972659abfc 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 5e759ec36f6a4329bda2f6fc1d13390a1b6b7074 Mon Sep 17 00:00:00 2001 +From d598c335dc15970f48e74d93a109b6d80697f5dc Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -40,7 +40,7 @@ Patchset: surface3 3 files changed, 24 insertions(+) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index 6c8fb7a4d..22797a53f 100644 +index 6c8fb7a4dde4..22797a53f4d8 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { @@ -58,7 +58,7 @@ index 6c8fb7a4d..22797a53f 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 29a403526..986f32132 100644 +index 29a403526cd9..986f32132c3d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3792,6 +3792,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -78,7 +78,7 @@ index 29a403526..986f32132 100644 /* * Match for the GPDwin which unfortunately uses somewhat diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0..0b930c91b 100644 +index e4c3492a0c28..0b930c91bccb 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { @@ -97,9 +97,9 @@ index e4c3492a0..0b930c91b 100644 }; -- -2.52.0 +2.53.0 -From 4a41660055f580887775fda819a09aae4e7fa4bb Mon Sep 17 00:00:00 2001 +From 5849be7532018da0d56de1d3648597f173ff0223 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -179,7 +179,7 @@ Patchset: surface3 1 file changed, 26 insertions(+) diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c -index 6074b7730..6aa3e1d6f 100644 +index 6074b7730e86..6aa3e1d6f160 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -25,6 +25,12 @@ @@ -230,5 +230,5 @@ index 6074b7730..6aa3e1d6f 100644 } -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 1b5fe41fb1..95b565358c 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From b6b1c95e100682c8674b3db7155f8bc60a453171 Mon Sep 17 00:00:00 2001 +From 3d72dae91f779722543a763290329c965d94cfa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -32,7 +32,7 @@ Patchset: mwifiex 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index a760de191..db9b20322 100644 +index a760de191fce..db9b203226a8 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) @@ -58,7 +58,7 @@ index a760de191..db9b20322 100644 mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1d..f46b06f8d 100644 +index dd6d21f1dbfd..f46b06f8d643 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -151,7 +151,7 @@ index dd6d21f1d..f46b06f8d 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964ae..5d30ae39d 100644 +index d6ff964aec5b..5d30ae39d65e 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -4,6 +4,7 @@ @@ -163,9 +163,9 @@ index d6ff964ae..5d30ae39d 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.52.0 +2.53.0 -From 6c0913443c9ba701b349a05f4f1672b1278b8f8b Mon Sep 17 00:00:00 2001 +From 10da3f28dfe78f0fc85e776fb4a9318672c8460a Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -187,7 +187,7 @@ Patchset: mwifiex 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index db9b20322..ffd0c1fe9 100644 +index db9b203226a8..ffd0c1fe9223 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, @@ -212,7 +212,7 @@ index db9b20322..ffd0c1fe9 100644 } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d..99b024ecb 100644 +index f46b06f8d643..99b024ecbade 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -306,7 +306,7 @@ index f46b06f8d..99b024ecb 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d..c14eb56eb 100644 +index 5d30ae39d65e..c14eb56eb911 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -5,6 +5,7 @@ @@ -318,9 +318,9 @@ index 5d30ae39d..c14eb56eb 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.52.0 +2.53.0 -From 72d0eb8d4a676652ec58e7e707e5f4cd6d51b30d Mon Sep 17 00:00:00 2001 +From 4742af64e44354d4c0123b80568357baa85657ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index a953fa9af..7e4670599 100644 +index 7c7955afa8e8..c1c464bf33c6 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index a953fa9af..7e4670599 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4194,6 +4196,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4201,6 +4203,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index a953fa9af..7e4670599 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index e749fc75b4..451a75f903 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 7d52f30be7f191a3f4206e6cb43b43c66b3b30df Mon Sep 17 00:00:00 2001 +From 853cab6601ae45ce72a53c0e4b197fa629cf4c1c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 9ae3595fb..b26a39c97 100644 +index 9ae3595fb698..b26a39c97998 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -41,6 +41,9 @@ static bool fw_diag_log; @@ -116,5 +116,5 @@ index 9ae3595fb..b26a39c97 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 71440801e0..6f8fd52265 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 0c42d3ef5be780bec2767ad0910ab96200ad50f8 Mon Sep 17 00:00:00 2001 +From 18e1d66c6674f50167c42c7dcad5980d60ba23c0 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index fa30899a5..a1864dcb7 100644 +index fa30899a5fa2..a1864dcb713d 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index fa30899a5..a1864dcb7 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 2a6e56955..c19dfba54 100644 +index 2a6e569558b9..c19dfba542c1 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -35,9 +35,9 @@ index 2a6e56955..c19dfba54 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.52.0 +2.53.0 -From 0dddf0a24b18680fa269a0d3a7b4c87597fc2535 Mon Sep 17 00:00:00 2001 +From 59ef9aacf5537d7ba1f014d17ce00e7cbac61d8d Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index e236c7ec2..9e31a5fe1 100644 +index 49e83c8566a3..a3e35c77da90 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -91,7 +91,7 @@ index e236c7ec2..9e31a5fe1 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -1879,6 +1886,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1881,6 +1888,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index e236c7ec2..9e31a5fe1 100644 } return 0; -@@ -2169,6 +2179,9 @@ static int __init init_dmars(void) +@@ -2171,6 +2181,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index e236c7ec2..9e31a5fe1 100644 check_tylersburg_isoch(); /* -@@ -4515,6 +4528,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4517,6 +4530,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index e236c7ec2..9e31a5fe1 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4553,6 +4578,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4555,6 +4580,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index e236c7ec2..9e31a5fe1 100644 { if (risky_device(dev)) -- -2.52.0 +2.53.0 -From 2d3ebe8da80b712d62f6556bd35bfec0cbd8855b Mon Sep 17 00:00:00 2001 +From fbce43d4605899b50b18f92ca5f9ca8b4c4f6bba Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,10 +211,10 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 04420a713..63b4eda94 100644 +index 03ad8b5c29a4..c639bb1f6733 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1439,6 +1439,8 @@ source "drivers/hid/surface-hid/Kconfig" +@@ -1440,6 +1440,8 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/intel-thc-hid/Kconfig" @@ -224,7 +224,7 @@ index 04420a713..63b4eda94 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 361a7daed..b73a1bbd3 100644 +index 361a7daedeb8..b73a1bbd3a1d 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -176,3 +176,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -235,7 +235,7 @@ index 361a7daed..b73a1bbd3 100644 +obj-$(CONFIG_HID_IPTS) += ipts/ diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 000000000..297401bd3 +index 000000000000..297401bd388d --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -255,7 +255,7 @@ index 000000000..297401bd3 + module will be called ipts. diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile new file mode 100644 -index 000000000..883896f68 +index 000000000000..883896f68e6a --- /dev/null +++ b/drivers/hid/ipts/Makefile @@ -0,0 +1,16 @@ @@ -277,7 +277,7 @@ index 000000000..883896f68 +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 000000000..63a4934bb +index 000000000000..63a4934bbc5f --- /dev/null +++ b/drivers/hid/ipts/cmd.c @@ -0,0 +1,61 @@ @@ -344,7 +344,7 @@ index 000000000..63a4934bb +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 000000000..2b4079075 +index 000000000000..2b4079075b64 --- /dev/null +++ b/drivers/hid/ipts/cmd.h @@ -0,0 +1,60 @@ @@ -410,7 +410,7 @@ index 000000000..2b4079075 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 000000000..ba33259f1 +index 000000000000..ba33259f1f7c --- /dev/null +++ b/drivers/hid/ipts/context.h @@ -0,0 +1,52 @@ @@ -468,7 +468,7 @@ index 000000000..ba33259f1 +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 000000000..5360842d2 +index 000000000000..5360842d260b --- /dev/null +++ b/drivers/hid/ipts/control.c @@ -0,0 +1,486 @@ @@ -960,7 +960,7 @@ index 000000000..5360842d2 +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 000000000..26629c514 +index 000000000000..26629c5144ed --- /dev/null +++ b/drivers/hid/ipts/control.h @@ -0,0 +1,126 @@ @@ -1092,7 +1092,7 @@ index 000000000..26629c514 +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 000000000..307438c7c +index 000000000000..307438c7c80c --- /dev/null +++ b/drivers/hid/ipts/desc.h @@ -0,0 +1,80 @@ @@ -1178,7 +1178,7 @@ index 000000000..307438c7c +#endif /* IPTS_DESC_H */ diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 000000000..7b9f54388 +index 000000000000..7b9f54388a9f --- /dev/null +++ b/drivers/hid/ipts/eds1.c @@ -0,0 +1,104 @@ @@ -1288,7 +1288,7 @@ index 000000000..7b9f54388 +} diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h new file mode 100644 -index 000000000..eeeb6575e +index 000000000000..eeeb6575e3e8 --- /dev/null +++ b/drivers/hid/ipts/eds1.h @@ -0,0 +1,35 @@ @@ -1329,7 +1329,7 @@ index 000000000..eeeb6575e + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c new file mode 100644 -index 000000000..639940794 +index 000000000000..639940794615 --- /dev/null +++ b/drivers/hid/ipts/eds2.c @@ -0,0 +1,145 @@ @@ -1480,7 +1480,7 @@ index 000000000..639940794 +} diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h new file mode 100644 -index 000000000..064e37169 +index 000000000000..064e3716907a --- /dev/null +++ b/drivers/hid/ipts/eds2.h @@ -0,0 +1,35 @@ @@ -1521,7 +1521,7 @@ index 000000000..064e37169 + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c new file mode 100644 -index 000000000..e34a1a4f9 +index 000000000000..e34a1a4f9fa7 --- /dev/null +++ b/drivers/hid/ipts/hid.c @@ -0,0 +1,225 @@ @@ -1752,7 +1752,7 @@ index 000000000..e34a1a4f9 +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 000000000..1ebe77447 +index 000000000000..1ebe77447903 --- /dev/null +++ b/drivers/hid/ipts/hid.h @@ -0,0 +1,24 @@ @@ -1782,7 +1782,7 @@ index 000000000..1ebe77447 +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 000000000..fb5b5c13e +index 000000000000..fb5b5c13ee3e --- /dev/null +++ b/drivers/hid/ipts/main.c @@ -0,0 +1,126 @@ @@ -1914,7 +1914,7 @@ index 000000000..fb5b5c13e +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 000000000..1e0395cea +index 000000000000..1e0395ceae4a --- /dev/null +++ b/drivers/hid/ipts/mei.c @@ -0,0 +1,188 @@ @@ -2108,7 +2108,7 @@ index 000000000..1e0395cea +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 000000000..973bade6b +index 000000000000..973bade6b0fd --- /dev/null +++ b/drivers/hid/ipts/mei.h @@ -0,0 +1,66 @@ @@ -2180,7 +2180,7 @@ index 000000000..973bade6b +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 000000000..977724c72 +index 000000000000..977724c728c3 --- /dev/null +++ b/drivers/hid/ipts/receiver.c @@ -0,0 +1,251 @@ @@ -2437,7 +2437,7 @@ index 000000000..977724c72 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 000000000..3de7da62d +index 000000000000..3de7da62d40c --- /dev/null +++ b/drivers/hid/ipts/receiver.h @@ -0,0 +1,16 @@ @@ -2459,7 +2459,7 @@ index 000000000..3de7da62d +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 000000000..cc14653b2 +index 000000000000..cc14653b2a9f --- /dev/null +++ b/drivers/hid/ipts/resources.c @@ -0,0 +1,131 @@ @@ -2596,7 +2596,7 @@ index 000000000..cc14653b2 +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 000000000..2068e1328 +index 000000000000..2068e13285f0 --- /dev/null +++ b/drivers/hid/ipts/resources.h @@ -0,0 +1,41 @@ @@ -2643,7 +2643,7 @@ index 000000000..2068e1328 +#endif /* IPTS_RESOURCES_H */ diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h new file mode 100644 -index 000000000..e8dd98895 +index 000000000000..e8dd98895a7e --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -2749,7 +2749,7 @@ index 000000000..e8dd98895 +#endif /* IPTS_SPEC_DATA_H */ diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h new file mode 100644 -index 000000000..41845f9d9 +index 000000000000..41845f9d9025 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h @@ -0,0 +1,290 @@ @@ -3045,7 +3045,7 @@ index 000000000..41845f9d9 +#endif /* IPTS_SPEC_DEVICE_H */ diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h new file mode 100644 -index 000000000..5a58d4a0a +index 000000000000..5a58d4a0a610 --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h @@ -0,0 +1,34 @@ @@ -3085,7 +3085,7 @@ index 000000000..5a58d4a0a +#endif /* IPTS_SPEC_HID_H */ diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c new file mode 100644 -index 000000000..355e92bea +index 000000000000..355e92bea26f --- /dev/null +++ b/drivers/hid/ipts/thread.c @@ -0,0 +1,84 @@ @@ -3175,7 +3175,7 @@ index 000000000..355e92bea +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 000000000..1f966b8b3 +index 000000000000..1f966b8b32c4 --- /dev/null +++ b/drivers/hid/ipts/thread.h @@ -0,0 +1,59 @@ @@ -3239,5 +3239,5 @@ index 000000000..1f966b8b3 + +#endif /* IPTS_THREAD_H */ -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index 90ef4fc94f..ac38167990 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From d52e2510add1b174d32ac5476fbee0138f642261 Mon Sep 17 00:00:00 2001 +From 7d42c081cbd40130068f7694756ba20ae0bafd2f Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,7 +10,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 8bcbfe3d9..c78806d35 100644 +index 8bcbfe3d9c72..c78806d35f2b 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) @@ -37,9 +37,9 @@ index 8bcbfe3d9..c78806d35 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.52.0 +2.53.0 -From bcae5998d9e659722f1c1912690efbe11afc13f9 Mon Sep 17 00:00:00 2001 +From 75c4b2e3d1698cf10235594c18d1c02d58d8ca6c Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,10 +86,10 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 63b4eda94..184a2b2f9 100644 +index c639bb1f6733..b148be159c6b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1441,6 +1441,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" +@@ -1442,6 +1442,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" source "drivers/hid/ipts/Kconfig" @@ -99,7 +99,7 @@ index 63b4eda94..184a2b2f9 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index b73a1bbd3..3190ece25 100644 +index b73a1bbd3a1d..3190ece25626 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -178,3 +178,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ @@ -109,7 +109,7 @@ index b73a1bbd3..3190ece25 100644 +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 000000000..4937ba131 +index 000000000000..4937ba131297 --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -121,7 +121,7 @@ index 000000000..4937ba131 + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 000000000..ede713023 +index 000000000000..ede713023609 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -139,7 +139,7 @@ index 000000000..ede713023 + module will be called ithc. diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c new file mode 100644 -index 000000000..2d8c6afe9 +index 000000000000..2d8c6afe9966 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,149 @@ @@ -294,7 +294,7 @@ index 000000000..2d8c6afe9 + diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h new file mode 100644 -index 000000000..38c53d916 +index 000000000000..38c53d916bdb --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.h @@ -0,0 +1,7 @@ @@ -307,7 +307,7 @@ index 000000000..38c53d916 + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 000000000..bf4eab330 +index 000000000000..bf4eab33062b --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,312 @@ @@ -625,7 +625,7 @@ index 000000000..bf4eab330 + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 000000000..1749a5819 +index 000000000000..1749a5819b3e --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,47 @@ @@ -678,7 +678,7 @@ index 000000000..1749a5819 + diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c new file mode 100644 -index 000000000..065646ab4 +index 000000000000..065646ab499e --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.c @@ -0,0 +1,207 @@ @@ -891,7 +891,7 @@ index 000000000..065646ab4 + diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h new file mode 100644 -index 000000000..599eb912c +index 000000000000..599eb912c8c8 --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.h @@ -0,0 +1,32 @@ @@ -929,7 +929,7 @@ index 000000000..599eb912c + diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c new file mode 100644 -index 000000000..8883987fb +index 000000000000..8883987fb352 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.c @@ -0,0 +1,254 @@ @@ -1189,7 +1189,7 @@ index 000000000..8883987fb + diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h new file mode 100644 -index 000000000..28d692462 +index 000000000000..28d692462072 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.h @@ -0,0 +1,8 @@ @@ -1203,7 +1203,7 @@ index 000000000..28d692462 + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000..094d878d6 +index 000000000000..094d878d671b --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,438 @@ @@ -1647,7 +1647,7 @@ index 000000000..094d878d6 + diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c new file mode 100644 -index 000000000..e2d1690b8 +index 000000000000..e2d1690b8cf8 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.c @@ -0,0 +1,607 @@ @@ -2260,7 +2260,7 @@ index 000000000..e2d1690b8 + diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h new file mode 100644 -index 000000000..74d882f6b +index 000000000000..74d882f6b2f0 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.h @@ -0,0 +1,39 @@ @@ -2305,7 +2305,7 @@ index 000000000..74d882f6b + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 000000000..c0f13506a +index 000000000000..c0f13506af20 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,154 @@ @@ -2465,7 +2465,7 @@ index 000000000..c0f13506a + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 000000000..4f541fe53 +index 000000000000..4f541fe533fa --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,211 @@ @@ -2682,7 +2682,7 @@ index 000000000..4f541fe53 + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 000000000..aec320d4e +index 000000000000..aec320d4e945 --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,89 @@ @@ -2776,5 +2776,5 @@ index 000000000..aec320d4e +int ithc_reset(struct ithc *ithc); + -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index f89d814fe8..75236c0112 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From d64b237185aec90aab4278469a5a826348065b3f Mon Sep 17 00:00:00 2001 +From c3acce9389f81f36c7b058da426ce0100868cab9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -14,7 +14,7 @@ Patchset: surface-sam create mode 100644 drivers/rtc/rtc-surface.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 2933c41c7..050eba74d 100644 +index 2933c41c77c8..050eba74d8a2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1399,6 +1399,13 @@ config RTC_DRV_NTXEC @@ -32,7 +32,7 @@ index 2933c41c7..050eba74d 100644 config RTC_DRV_ASM9260 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile -index 8221bda6e..8932df6e0 100644 +index 8221bda6e6dc..8932df6e03ed 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -183,6 +183,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o @@ -45,7 +45,7 @@ index 8221bda6e..8932df6e0 100644 obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c new file mode 100644 -index 000000000..f6c17c4e9 +index 000000000000..f6c17c4e98d5 --- /dev/null +++ b/drivers/rtc/rtc-surface.c @@ -0,0 +1,129 @@ @@ -179,9 +179,9 @@ index 000000000..f6c17c4e9 +MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.52.0 +2.53.0 -From 9a5f80d5b74c3ff8d31f2b22e37bcc4792d91a23 Mon Sep 17 00:00:00 2001 +From 359f7cc1069466c3a1d0547ceca9698be5ec73b3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -193,7 +193,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index a594d5fcf..07b03aa4f 100644 +index a594d5fcfcfd..07b03aa4fa7f 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { @@ -207,5 +207,5 @@ index a594d5fcf..07b03aa4f 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index d844488d6c..5a1831fa27 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From aea01d05f5e71da926fbac44c158ce1d7fe98562 Mon Sep 17 00:00:00 2001 +From 9551995eeeb816e07eb73e6b670dee6ed3a245cc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,7 +55,7 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index ed90858a2..070c36637 100644 +index ed90858a27b7..070c36637811 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, @@ -107,9 +107,9 @@ index ed90858a2..070c36637 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.52.0 +2.53.0 -From 08a08c034bbc0f8d4c11ff60c7d078c6de5542af Mon Sep 17 00:00:00 2001 +From b15892ae4dacdc44e48aabd878cb273088943361 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -132,7 +132,7 @@ Patchset: surface-sam-over-hid create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index f775c6ca1..2075e3852 100644 +index f775c6ca1ec1..2075e3852053 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH @@ -150,7 +150,7 @@ index f775c6ca1..2075e3852 100644 tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 533443309..7efcd0cdb 100644 +index 53344330939b..7efcd0cdb532 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o @@ -163,7 +163,7 @@ index 533443309..7efcd0cdb 100644 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 000000000..68db23773 +index 000000000000..68db237734a1 --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c @@ -0,0 +1,136 @@ @@ -304,5 +304,5 @@ index 000000000..68db23773 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 9daa7778bb..d03deeca40 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From cad7c632ef22427f26dceb4e1a3b0d5d143991d8 Mon Sep 17 00:00:00 2001 +From 35d4534f1ed90419bdd7ac2d82f7e88c156ef02b Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -20,7 +20,7 @@ Patchset: surface-button 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index b8cad415c..43b5d5638 100644 +index b8cad415c62c..43b5d56383e3 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -73,9 +73,9 @@ index b8cad415c..43b5d5638 100644 /* -- -2.52.0 +2.53.0 -From f1c04affde903b94f8cd1e37c48a6a92dc280443 Mon Sep 17 00:00:00 2001 +From 0503cd4c3347f1fec8e292a91d1e5d780187750d Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -96,7 +96,7 @@ Patchset: surface-button 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f9..4240c98ca 100644 +index 2755601f979c..4240c98ca226 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) @@ -145,5 +145,5 @@ index 2755601f9..4240c98ca 100644 -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index afc3149225..232e5bc267 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 7480aa8ac22d073ca9e6d56305bcf7eb578955e9 Mon Sep 17 00:00:00 2001 +From ac09d90b18735c08f468036d4463748f98079b1e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index c4d85089d..3d0d35c72 100644 +index c4d85089d19b..3d0d35c72189 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -37,9 +37,9 @@ index c4d85089d..3d0d35c72 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.52.0 +2.53.0 -From 09d6209e5e3de8e20d764975e783a155ede483ce Mon Sep 17 00:00:00 2001 +From d15dc69b0a2269a35fee0523996600992957a164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index a0c1ad5ac..2cd18fe61 100644 +index 4dcb1d43df27..41e73a6aeed3 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -97,11 +97,11 @@ index a0c1ad5ac..2cd18fe61 100644 #include "hid-haptic.h" -@@ -76,12 +80,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) +@@ -77,12 +81,15 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_ORIENTATION_INVERT BIT(22) #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) + #define MT_QUIRK_YOGABOOK9I BIT(24) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -113,7 +113,7 @@ index a0c1ad5ac..2cd18fe61 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -184,6 +191,8 @@ struct mt_device { +@@ -185,6 +192,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -122,17 +122,17 @@ index a0c1ad5ac..2cd18fe61 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -229,6 +238,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 +@@ -231,6 +240,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_SMART_TECH 0x0113 #define MT_CLS_APPLE_TOUCHBAR 0x0114 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 + #define MT_CLS_YOGABOOK9I 0x0115 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0116 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -426,6 +436,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE, +@@ -436,6 +446,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_YOGABOOK9I, + .export_all_inputs = true }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -147,7 +147,7 @@ index a0c1ad5ac..2cd18fe61 100644 { } }; -@@ -1843,6 +1863,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1909,6 +1929,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index a0c1ad5ac..2cd18fe61 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1871,6 +1954,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1937,6 +2020,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index a0c1ad5ac..2cd18fe61 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1909,8 +1995,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1975,8 +2061,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index a0c1ad5ac..2cd18fe61 100644 if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && !hid_find_field(hdev, HID_INPUT_REPORT, -@@ -1924,8 +2012,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1990,8 +2078,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index a0c1ad5ac..2cd18fe61 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1986,6 +2076,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -2052,6 +2142,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index a0c1ad5ac..2cd18fe61 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2430,6 +2521,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2505,6 +2596,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, @@ -272,9 +272,9 @@ index a0c1ad5ac..2cd18fe61 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.52.0 +2.53.0 -From 9a451e7c0c26329ad8e334238c601cc2e1c4cf0a Mon Sep 17 00:00:00 2001 +From 9c77a5c88f6899ea31e32f54cf4deb192e74f67e Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,18 +303,18 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 2cd18fe61..c4179f6c3 100644 +index 41e73a6aeed3..1d245e998687 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -81,6 +81,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) +@@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) + #define MT_QUIRK_YOGABOOK9I BIT(24) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -88,6 +89,8 @@ MODULE_LICENSE("GPL"); +@@ -89,6 +90,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_CLICKPAD 0 #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 @@ -323,7 +323,7 @@ index 2cd18fe61..c4179f6c3 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -438,6 +441,7 @@ static const struct mt_class mt_classes[] = { +@@ -448,6 +451,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -331,7 +331,7 @@ index 2cd18fe61..c4179f6c3 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1464,6 +1468,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1474,6 +1478,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -341,7 +341,7 @@ index 2cd18fe61..c4179f6c3 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1491,6 +1498,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1501,6 +1508,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -363,7 +363,7 @@ index 2cd18fe61..c4179f6c3 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1517,6 +1539,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1527,6 +1549,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -371,7 +371,7 @@ index 2cd18fe61..c4179f6c3 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1524,6 +1547,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1534,6 +1557,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -391,7 +391,7 @@ index 2cd18fe61..c4179f6c3 100644 /* let hid-core decide for the others */ return 0; } -@@ -1533,11 +1569,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1543,11 +1579,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -413,7 +413,7 @@ index 2cd18fe61..c4179f6c3 100644 return 0; } -@@ -1720,6 +1766,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1762,6 +1808,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index 2cd18fe61..c4179f6c3 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1777,6 +1859,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1819,6 +1901,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 2cd18fe61..c4179f6c3 100644 default: suffix = "UNKNOWN"; break; -@@ -1863,30 +1952,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1929,30 +2018,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 2cd18fe61..c4179f6c3 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1895,8 +1960,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1961,8 +2026,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 2cd18fe61..c4179f6c3 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -2054,13 +2120,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -2120,13 +2186,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 2cd18fe61..c4179f6c3 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -2069,12 +2146,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -2135,12 +2212,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); @@ -571,5 +571,5 @@ index 2cd18fe61..c4179f6c3 100644 unregister_pm_notifier(&td->pm_notifier); timer_delete_sync(&td->release_timer); -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index b4c609ada6..26e3bf2602 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From f6f5d63846d4b868464b914ec63baf2ef000d95a Mon Sep 17 00:00:00 2001 +From 5010a105a1ebf3d060a46f962aae9d9ac41eed83 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 327b21c48..51dd5e10f 100644 +index b4111c92c957..9c3db65ea09b 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,10 +37,10 @@ index 327b21c48..51dd5e10f 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index b9c252aa6..ce4c0da99 100644 +index d32a47e81fcf..68b9a0563731 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6341,3 +6341,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6378,3 +6378,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -81,10 +81,10 @@ index b9c252aa6..ce4c0da99 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index bf97d49c2..90eead93d 100644 +index 05aeee8c8844..006ea71cef1b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -487,6 +487,7 @@ struct pci_dev { +@@ -488,6 +488,7 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ @@ -93,9 +93,9 @@ index bf97d49c2..90eead93d 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.52.0 +2.53.0 -From e37ed31e23703d9f2f210e26677d41ef3dde634b Mon Sep 17 00:00:00 2001 +From de2551858b340e1eca868a48767be786ddcd30f1 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops @@ -108,10 +108,10 @@ Patchset: surface-shutdown 1 file changed, 13 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index ce4c0da99..fdc410bf7 100644 +index 68b9a0563731..848fd74a775f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6360,6 +6360,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { +@@ -6397,6 +6397,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), }, }, @@ -125,7 +125,7 @@ index ce4c0da99..fdc410bf7 100644 {} }; -@@ -6377,3 +6384,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thu +@@ -6414,3 +6421,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thu DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU @@ -136,5 +136,5 @@ index ce4c0da99..fdc410bf7 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa73e, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa7a0, quirk_no_shutdown); // GPU -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index e96101ebb4..8badf84750 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From fe14472400b7156fb3fdb8fc9108018da180da32 Mon Sep 17 00:00:00 2001 +From f1b7bd8c2b1ba59bd171cfdc4fdd2532769cfaac Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -12,7 +12,7 @@ Patchset: surface-gpe 1 file changed, 17 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index b35941390..b4496db79 100644 +index b359413903b1..b4496db79f39 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { @@ -47,5 +47,5 @@ index b35941390..b4496db79 100644 .ident = "Surface Book 1", .matches = { -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index 4cd22fd07c..0b957173d0 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From 79d2acffafb8f9dfd0615feaf3681ad6f544654b Mon Sep 17 00:00:00 2001 +From 4ccebffe3c5044049d60aebb0f1e64eb911825d4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,7 +58,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index ef16d58b2..a6bad2679 100644 +index ef16d58b2949..a6bad2679a0c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, @@ -72,9 +72,9 @@ index ef16d58b2..a6bad2679 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.52.0 +2.53.0 -From 8d0914e088c9a8303ff59fd76b0efb63fcb66fcb Mon Sep 17 00:00:00 2001 +From b2793a669d10aba569fe0dd5bee851fab29b26fb Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 9e31a5fe1..bdd32551c 100644 +index a3e35c77da90..28567ba59de4 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -132,7 +132,7 @@ index 9e31a5fe1..bdd32551c 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -1887,6 +1896,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1889,6 +1898,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index 9e31a5fe1..bdd32551c 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2179,6 +2191,9 @@ static int __init init_dmars(void) +@@ -2181,6 +2193,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index 9e31a5fe1..bdd32551c 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4528,6 +4543,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4530,6 +4545,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index 9e31a5fe1..bdd32551c 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4578,6 +4605,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4580,6 +4607,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index 9e31a5fe1..bdd32551c 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.52.0 +2.53.0 -From d5b1ddd3cc136ba7710e4781a4bcd08fea0ed6fa Mon Sep 17 00:00:00 2001 +From 9e9809390e599e8ad59e47487ec0f0d9a21ab556 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -201,7 +201,7 @@ Patchset: cameras 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 013340569..9e0763bdc 100644 +index 0133405697dc..9e0763bdc758 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) @@ -219,9 +219,9 @@ index 013340569..9e0763bdc 100644 return 0; -- -2.52.0 +2.53.0 -From 4d89428772cec0f47fba2a04dd663f21df1d20d6 Mon Sep 17 00:00:00 2001 +From 1a9ca756632807162e489ba940405af73c6fce45 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -236,7 +236,7 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 27afc3fc0..28b192c9a 100644 +index 27afc3fc0175..28b192c9a5ec 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) @@ -258,9 +258,9 @@ index 27afc3fc0..28b192c9a 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.52.0 +2.53.0 -From 12273c1327ac6f6249dc771f125dfb4a93583593 Mon Sep 17 00:00:00 2001 +From 55f59684a4c93142c48689ac16c14993bec38524 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -279,10 +279,10 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index ee884a822..4f6bafd90 100644 +index 1c08bba9ecb9..57a990d7dc84 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c -@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) +@@ -811,6 +811,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) INIT_LIST_HEAD(&sd->asc_list); @@ -294,7 +294,7 @@ index ee884a822..4f6bafd90 100644 * No reference taken. The reference is held by the device (struct * v4l2_subdev.dev), and async sub-device does not exist independently diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index cb153ce42..f11b499e1 100644 +index cb153ce42c45..f11b499e14bb 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) @@ -309,9 +309,9 @@ index cb153ce42..f11b499e1 100644 if (ret < 0) goto out_cleanup; -- -2.52.0 +2.53.0 -From a1d8907d34da038a7caeeae5258de037db32b48d Mon Sep 17 00:00:00 2001 +From 89a08d9e3f3aaa82e181c9f285d8cad0941adf30 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -327,7 +327,7 @@ Patchset: cameras 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 9e0763bdc..0976b2679 100644 +index 9e0763bdc758..0976b267972b 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -350,9 +350,9 @@ index 9e0763bdc..0976b2679 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.52.0 +2.53.0 -From 16d8bb8adce156323c6c2d698fbbfc3846a5a760 Mon Sep 17 00:00:00 2001 +From 8cd7dfb19952f84d817c9a9c98ba6c16d7751e25 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -370,7 +370,7 @@ Patchset: cameras 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329..2d2abb25b 100644 +index 7807fa329db0..2d2abb25b944 100644 --- a/include/linux/mfd/tps68470.h +++ b/include/linux/mfd/tps68470.h @@ -34,6 +34,7 @@ @@ -391,9 +391,9 @@ index 7807fa329..2d2abb25b 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.52.0 +2.53.0 -From 93b8ec92a713fbe3846eee21d24f4b1a53dea456 Mon Sep 17 00:00:00 2001 +From fa209f059f1750824fb0258d6815d842a0dde04d Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -416,7 +416,7 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 06e6291be..8f94924ef 100644 +index 06e6291be11b..8f94924ef379 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -1002,6 +1002,18 @@ config LEDS_TPS6105X @@ -439,7 +439,7 @@ index 06e6291be..8f94924ef 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 9a0333ec1..4e1ca8fc9 100644 +index 9a0333ec1a86..4e1ca8fc9b41 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o @@ -452,7 +452,7 @@ index 9a0333ec1..4e1ca8fc9 100644 obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c new file mode 100644 -index 000000000..35aeb5db8 +index 000000000000..35aeb5db89c8 --- /dev/null +++ b/drivers/leds/leds-tps68470.c @@ -0,0 +1,185 @@ @@ -642,9 +642,9 @@ index 000000000..35aeb5db8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.52.0 +2.53.0 -From f8485df32505cd4f3ab155c0723dac20fc4c6cc4 Mon Sep 17 00:00:00 2001 +From 379d2ee8283e4a1778256aae1e05e5d0c271fe60 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -660,7 +660,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index 032fbcb98..e03a1d8cd 100644 +index 032fbcb981f2..e03a1d8cdcb4 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c @@ -87,6 +87,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) @@ -674,9 +674,9 @@ index 032fbcb98..e03a1d8cd 100644 cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); fsleep(100); -- -2.52.0 +2.53.0 -From ce276ac4c6169e6194f4af489a6aaa9d91b022fd Mon Sep 17 00:00:00 2001 +From 45e1b6ea63062039adb5b7a1204510d69ed8aa10 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 @@ -693,7 +693,7 @@ Patchset: cameras 4 files changed, 184 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c -index 162b49046..85cd0c98a 100644 +index 162b49046990..85cd0c98af03 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -2,6 +2,7 @@ @@ -940,7 +940,7 @@ index 162b49046..85cd0c98a 100644 }, .probe = ov13858_probe, diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c -index d294477f9..46bc6c5b7 100644 +index d294477f9dd3..46bc6c5b7758 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -1396,6 +1396,7 @@ static const struct dev_pm_ops ov5693_pm_ops = { @@ -952,7 +952,7 @@ index d294477f9..46bc6c5b7 100644 }; MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c -index 4e579352a..ac637207b 100644 +index 4e579352ab2c..ac637207b644 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -60,6 +60,10 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { @@ -967,7 +967,7 @@ index 4e579352a..ac637207b 100644 IPU_SENSOR_CONFIG("INT3474", 1, 180000000), /* Omnivision OV5670 */ diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 1505fc3ef..20962e8ac 100644 +index 1505fc3ef7a8..20962e8acb26 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -229,6 +229,14 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 @@ -1015,5 +1015,5 @@ index 1505fc3ef..20962e8ac 100644 ret = -EINVAL; break; -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 22572d8aa6..51dfa5c998 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 69c528d432300afb2d6f516bbeb5387f604f7c1a Mon Sep 17 00:00:00 2001 +From 1b73858484a66b2fdc5c1e22f1845e33afe0a22e Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 9fa321a95..8914a922b 100644 +index 9fa321a95eb3..8914a922be2b 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -63,9 +63,9 @@ index 9fa321a95..8914a922b 100644 mp_config_acpi_legacy_irqs(); -- -2.52.0 +2.53.0 -From ed986760aea58b450fd5d68a7680e5e89b13b956 Mon Sep 17 00:00:00 2001 +From 20b7f69698f47be78cc922dd35f0942a3af8e911 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,7 +80,7 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 8914a922b..c43d0a553 100644 +index 8914a922be2b..c43d0a553867 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) @@ -105,5 +105,5 @@ index 8914a922b..c43d0a553 100644 }; -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index f9ecbe14a7..4868098785 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 572c4db540d3260d10f88fe175faa8b095e81d47 Mon Sep 17 00:00:00 2001 +From 79a919027e012ab08f38a30d56de017469eabf61 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 33418dd67..f94bbdc1d 100644 +index 33418dd6768a..f94bbdc1de06 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, @@ -106,5 +106,5 @@ index 33418dd67..f94bbdc1d 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index cd2b73ef15..b06e7370ef 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From fcc0ca5789466264c908c7a793ee86f7848d3460 Mon Sep 17 00:00:00 2001 +From 4bf41a1c274e5a0bd33c2686b3d5ae676b31a876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -27,10 +27,10 @@ Patchset: hid-surface create mode 100644 drivers/hid/hid-surface.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 184a2b2f9..d2e308b25 100644 +index b148be159c6b..fd70eb54a0ea 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1141,6 +1141,14 @@ config HID_SUNPLUS +@@ -1142,6 +1142,14 @@ config HID_SUNPLUS help Support for Sunplus wireless desktop. @@ -46,7 +46,7 @@ index 184a2b2f9..d2e308b25 100644 tristate "Synaptics RMI4 device support" select RMI4_CORE diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 3190ece25..4d2891879 100644 +index 3190ece25626..4d2891879548 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -174,6 +174,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ @@ -59,7 +59,7 @@ index 3190ece25..4d2891879 100644 diff --git a/drivers/hid/hid-surface.c b/drivers/hid/hid-surface.c new file mode 100644 -index 000000000..a171ea656 +index 000000000000..a171ea65672f --- /dev/null +++ b/drivers/hid/hid-surface.c @@ -0,0 +1,90 @@ @@ -154,9 +154,9 @@ index 000000000..a171ea656 +MODULE_DESCRIPTION("Microsoft Surface HID driver"); +MODULE_LICENSE("GPL"); -- -2.52.0 +2.53.0 -From 49aefa6d21438030fd0b59bbccaff01540ee679b Mon Sep 17 00:00:00 2001 +From f558115833c7f39820424ffbf9b9b05fde7ef26f Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 @@ -168,26 +168,26 @@ Patchset: hid-surface 1 file changed, 30 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index c4179f6c3..d59fe2185 100644 +index 1d245e998687..4d09710df6ba 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) - #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) -+#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(26) +@@ -83,6 +83,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_YOGABOOK9I BIT(24) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) + #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) ++#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(27) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -242,6 +243,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_SMART_TECH 0x0113 +@@ -244,6 +245,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_APPLE_TOUCHBAR 0x0114 - #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 -+#define MT_CLS_SURFACE_TOUCHPAD 0x0116 + #define MT_CLS_YOGABOOK9I 0x0115 + #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0116 ++#define MT_CLS_SURFACE_TOUCHPAD 0x0117 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -450,6 +452,10 @@ static const struct mt_class mt_classes[] = { +@@ -460,6 +462,10 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_WIN8_PTP_BUTTONS, .export_all_inputs = true }, @@ -198,7 +198,7 @@ index c4179f6c3..d59fe2185 100644 { } }; -@@ -2181,11 +2187,30 @@ static void mt_remove(struct hid_device *hdev) +@@ -2247,11 +2253,30 @@ static void mt_remove(struct hid_device *hdev) static void mt_on_hid_hw_open(struct hid_device *hdev) { @@ -229,7 +229,7 @@ index c4179f6c3..d59fe2185 100644 mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); } -@@ -2622,6 +2647,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2697,6 +2722,11 @@ static const struct hid_device_id mt_devices[] = { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_MICROSOFT, 0x09c0) }, @@ -242,5 +242,5 @@ index c4179f6c3..d59fe2185 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.52.0 +2.53.0 diff --git a/patches/6.18/0017-powercap.patch b/patches/6.18/0017-powercap.patch deleted file mode 100644 index 68f5a19ecb..0000000000 --- a/patches/6.18/0017-powercap.patch +++ /dev/null @@ -1,30 +0,0 @@ -From c142c6d09d7d2d877c7e590d90d9c0aa2b6dd075 Mon Sep 17 00:00:00 2001 -From: Daniel Tang -Date: Wed, 14 Jan 2026 20:31:38 -0500 -Subject: [PATCH] powercap: intel_rapl: Add PL4 support for Ice Lake - -Microsoft Surface Pro 7 firmware throttles the processor upon -boot/resume. Userspace needs to be able to restore the correct value. - -Link: https://github.com/linux-surface/linux-surface/issues/706 -Signed-off-by: Daniel Tang -Patchset: powercap ---- - drivers/powercap/intel_rapl_msr.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c -index c6b9a7deb..e82724768 100644 ---- a/drivers/powercap/intel_rapl_msr.c -+++ b/drivers/powercap/intel_rapl_msr.c -@@ -140,6 +140,7 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra) - - /* List of verified CPUs. */ - static const struct x86_cpu_id pl4_support_ids[] = { -+ X86_MATCH_VFM(INTEL_ICELAKE_L, NULL), - X86_MATCH_VFM(INTEL_TIGERLAKE_L, NULL), - X86_MATCH_VFM(INTEL_ALDERLAKE, NULL), - X86_MATCH_VFM(INTEL_ALDERLAKE_L, NULL), --- -2.52.0 - From 36e1ce396ee175ffbff0f9cb5e64cfcfb44798d3 Mon Sep 17 00:00:00 2001 From: Cornell Chin Date: Thu, 12 Mar 2026 14:47:18 -0400 Subject: [PATCH 206/236] Update v6.18 patches Changes: - Rebase onto v6.18.17 --- patches/6.18/0001-secureboot.patch | 4 +- patches/6.18/0002-surface3.patch | 4 +- patches/6.18/0003-mwifiex.patch | 6 +- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 6 +- patches/6.18/0006-ithc.patch | 4 +- patches/6.18/0007-surface-sam.patch | 4 +- patches/6.18/0008-surface-sam-over-hid.patch | 4 +- patches/6.18/0009-surface-button.patch | 4 +- patches/6.18/0010-surface-typecover.patch | 76 ++++++++++---------- patches/6.18/0011-surface-shutdown.patch | 4 +- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 20 +++--- patches/6.18/0014-amd-gpio.patch | 14 ++-- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 41 ++++++----- 16 files changed, 98 insertions(+), 99 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 18249af940..37a4c9befb 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 1c440464ed3603305d6d9a862597fc17aff88726 Mon Sep 17 00:00:00 2001 +From 61fc15e4514027eab8823c4ccf8d0a41c8216210 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 -- 2.53.0 -From adefb036d5f0a08f88f9e3c06d599ab5fb45fa62 Mon Sep 17 00:00:00 2001 +From 27d5939b7a9289fef58883081d3281f6cb37bdd0 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index 972659abfc..961ac9bfde 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From d598c335dc15970f48e74d93a109b6d80697f5dc Mon Sep 17 00:00:00 2001 +From 2a24daccdb289b2937cc01a80be1889a14558665 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.53.0 -From 5849be7532018da0d56de1d3648597f173ff0223 Mon Sep 17 00:00:00 2001 +From 7a9c5e5d6ed881c6960966fad30834d365882797 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 95b565358c..832c99c739 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 3d72dae91f779722543a763290329c965d94cfa7 Mon Sep 17 00:00:00 2001 +From 353b617522ef72033f62db75e05294493bbdde0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.53.0 -From 10da3f28dfe78f0fc85e776fb4a9318672c8460a Mon Sep 17 00:00:00 2001 +From c66ba3aa77362a3173d0d23fc073a385caa375d4 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.53.0 -From 4742af64e44354d4c0123b80568357baa85657ee Mon Sep 17 00:00:00 2001 +From 5585932011c9eea7f063af12a4bd60d3310b63ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index 451a75f903..cae53cbcea 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 853cab6601ae45ce72a53c0e4b197fa629cf4c1c Mon Sep 17 00:00:00 2001 +From 6828bb428bbf9154633f460dbbeb1f0cb195f06d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 6f8fd52265..03e0fe128f 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 18e1d66c6674f50167c42c7dcad5980d60ba23c0 Mon Sep 17 00:00:00 2001 +From aadb8ddca607fee65fb1aa22734667883907fbac Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e569558b9..c19dfba542c1 100644 -- 2.53.0 -From 59ef9aacf5537d7ba1f014d17ce00e7cbac61d8d Mon Sep 17 00:00:00 2001 +From 2826c58e75292d4ee0af2cc2c924ab0a224916b1 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index 49e83c8566a3..a3e35c77da90 100644 -- 2.53.0 -From fbce43d4605899b50b18f92ca5f9ca8b4c4f6bba Mon Sep 17 00:00:00 2001 +From e8b9fe4bc745cb31da8c13853d562e02806aed13 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index ac38167990..2c8f5aaadc 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From 7d42c081cbd40130068f7694756ba20ae0bafd2f Mon Sep 17 00:00:00 2001 +From 1b77daa3d810df158d892a3874f9ea3086bb988d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9c72..c78806d35f2b 100644 -- 2.53.0 -From 75c4b2e3d1698cf10235594c18d1c02d58d8ca6c Mon Sep 17 00:00:00 2001 +From 2182d874f3a525a08c81bc3ea2233a9340bdb7f2 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index 75236c0112..7a56dd4804 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From c3acce9389f81f36c7b058da426ce0100868cab9 Mon Sep 17 00:00:00 2001 +From 2374c2db81f54300a089ab54a33ad51e6c6c7ccb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.53.0 -From 359f7cc1069466c3a1d0547ceca9698be5ec73b3 Mon Sep 17 00:00:00 2001 +From fffc105ff47eebcb30716b54b31577a16c8908f2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 5a1831fa27..5abedee3d6 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 9551995eeeb816e07eb73e6b670dee6ed3a245cc Mon Sep 17 00:00:00 2001 +From 09a3f9ef6f43e4810c6288655a9ef3880cff8f9a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a27b7..070c36637811 100644 -- 2.53.0 -From b15892ae4dacdc44e48aabd878cb273088943361 Mon Sep 17 00:00:00 2001 +From 2b22b6f1c814aa1ad36bb0a7eff2b6f7baa6c8dd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index d03deeca40..9cc2711149 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 35d4534f1ed90419bdd7ac2d82f7e88c156ef02b Mon Sep 17 00:00:00 2001 +From b1f6aead4130f4a4380145311d386671de8fb858 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.53.0 -From 0503cd4c3347f1fec8e292a91d1e5d780187750d Mon Sep 17 00:00:00 2001 +From 88a4b033d52b0e708b81e3b5fbb55d0f74911aed Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index 232e5bc267..e8a64bbaeb 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From ac09d90b18735c08f468036d4463748f98079b1e Mon Sep 17 00:00:00 2001 +From d57e717c711d9d85f60b34787f041063e1e9e031 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c4d85089d19b..3d0d35c72189 100644 -- 2.53.0 -From d15dc69b0a2269a35fee0523996600992957a164 Mon Sep 17 00:00:00 2001 +From 23de036a4048527398fa6e8435a66b9968b818a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 4dcb1d43df27..41e73a6aeed3 100644 +index af19e089b012..ab040ea64e28 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -97,11 +97,11 @@ index 4dcb1d43df27..41e73a6aeed3 100644 #include "hid-haptic.h" -@@ -77,12 +81,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) +@@ -78,12 +82,15 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) #define MT_QUIRK_YOGABOOK9I BIT(24) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) + #define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(26) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -113,7 +113,7 @@ index 4dcb1d43df27..41e73a6aeed3 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -185,6 +192,8 @@ struct mt_device { +@@ -186,6 +193,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -122,17 +122,17 @@ index 4dcb1d43df27..41e73a6aeed3 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -231,6 +240,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_SMART_TECH 0x0113 +@@ -234,6 +243,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_APPLE_TOUCHBAR 0x0114 #define MT_CLS_YOGABOOK9I 0x0115 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0116 + #define MT_CLS_EGALAX_P80H84 0x0116 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0117 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -436,6 +446,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_YOGABOOK9I, - .export_all_inputs = true +@@ -453,6 +463,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_CONTACT_CNT_ACCURATE, }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -147,7 +147,7 @@ index 4dcb1d43df27..41e73a6aeed3 100644 { } }; -@@ -1909,6 +1929,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1928,6 +1948,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index 4dcb1d43df27..41e73a6aeed3 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1937,6 +2020,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1956,6 +2039,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index 4dcb1d43df27..41e73a6aeed3 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1975,8 +2061,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1994,8 +2080,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index 4dcb1d43df27..41e73a6aeed3 100644 if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && !hid_find_field(hdev, HID_INPUT_REPORT, -@@ -1990,8 +2078,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -2009,8 +2097,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index 4dcb1d43df27..41e73a6aeed3 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -2052,6 +2142,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -2071,6 +2161,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index 4dcb1d43df27..41e73a6aeed3 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2505,6 +2596,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2538,6 +2629,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, @@ -274,7 +274,7 @@ index 4dcb1d43df27..41e73a6aeed3 100644 -- 2.53.0 -From 9c77a5c88f6899ea31e32f54cf4deb192e74f67e Mon Sep 17 00:00:00 2001 +From 9c94ebf4630a38563fc50f553e9293666943c538 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,18 +303,18 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 41e73a6aeed3..1d245e998687 100644 +index ab040ea64e28..ee9c073af9b4 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) +@@ -83,6 +83,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_YOGABOOK9I BIT(24) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) + #define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(26) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(27) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -89,6 +90,8 @@ MODULE_LICENSE("GPL"); +@@ -90,6 +91,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_CLICKPAD 0 #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 @@ -323,7 +323,7 @@ index 41e73a6aeed3..1d245e998687 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -448,6 +451,7 @@ static const struct mt_class mt_classes[] = { +@@ -465,6 +468,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -331,7 +331,7 @@ index 41e73a6aeed3..1d245e998687 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1474,6 +1478,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1492,6 +1496,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -341,7 +341,7 @@ index 41e73a6aeed3..1d245e998687 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1501,6 +1508,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1519,6 +1526,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -363,7 +363,7 @@ index 41e73a6aeed3..1d245e998687 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1527,6 +1549,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1545,6 +1567,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -371,7 +371,7 @@ index 41e73a6aeed3..1d245e998687 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1534,6 +1557,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1552,6 +1575,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -391,7 +391,7 @@ index 41e73a6aeed3..1d245e998687 100644 /* let hid-core decide for the others */ return 0; } -@@ -1543,11 +1579,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1561,11 +1597,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -413,7 +413,7 @@ index 41e73a6aeed3..1d245e998687 100644 return 0; } -@@ -1762,6 +1808,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1780,6 +1826,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index 41e73a6aeed3..1d245e998687 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1819,6 +1901,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1838,6 +1920,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 41e73a6aeed3..1d245e998687 100644 default: suffix = "UNKNOWN"; break; -@@ -1929,30 +2018,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1948,30 +2037,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 41e73a6aeed3..1d245e998687 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1961,8 +2026,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1980,8 +2045,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 41e73a6aeed3..1d245e998687 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -2120,13 +2186,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -2139,13 +2205,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 41e73a6aeed3..1d245e998687 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -2135,12 +2212,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -2154,12 +2231,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index 26e3bf2602..20a2e4f82a 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 5010a105a1ebf3d060a46f962aae9d9ac41eed83 Mon Sep 17 00:00:00 2001 +From f8b71f296d6df170fbccbe79edf6b7dbea1ad1a1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index 05aeee8c8844..006ea71cef1b 100644 -- 2.53.0 -From de2551858b340e1eca868a48767be786ddcd30f1 Mon Sep 17 00:00:00 2001 +From 0db99235b7a2046ae056953165e2b32d7338a45b Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index 8badf84750..fae3240a13 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From f1b7bd8c2b1ba59bd171cfdc4fdd2532769cfaac Mon Sep 17 00:00:00 2001 +From 0f90f3e26f3bb5459d6e294cf175416991d57a2c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index 0b957173d0..c12546ef45 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From 4ccebffe3c5044049d60aebb0f1e64eb911825d4 Mon Sep 17 00:00:00 2001 +From 47b14611fae19a28fdf526bf965d399e83a578d8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2949..a6bad2679a0c 100644 -- 2.53.0 -From b2793a669d10aba569fe0dd5bee851fab29b26fb Mon Sep 17 00:00:00 2001 +From b8ecbeb462117061326fd44bc4d55471c4e60aab Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index a3e35c77da90..28567ba59de4 100644 -- 2.53.0 -From 9e9809390e599e8ad59e47487ec0f0d9a21ab556 Mon Sep 17 00:00:00 2001 +From 1d2553a63ea1cc01c78e54cdf2a8445a22bf0fa9 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.53.0 -From 1a9ca756632807162e489ba940405af73c6fce45 Mon Sep 17 00:00:00 2001 +From d9cfd9e91d2c8bf63fbc3ded79deb9819ddc1936 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0175..28b192c9a5ec 100644 -- 2.53.0 -From 55f59684a4c93142c48689ac16c14993bec38524 Mon Sep 17 00:00:00 2001 +From ee2b87e57a62013bfa325335222f4139429170d7 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.53.0 -From 89a08d9e3f3aaa82e181c9f285d8cad0941adf30 Mon Sep 17 00:00:00 2001 +From c07f2a70d623be6cf766c41746bfcd5f274da66e Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.53.0 -From 8cd7dfb19952f84d817c9a9c98ba6c16d7751e25 Mon Sep 17 00:00:00 2001 +From 32c23d5ec76cc6b256dd805dff4c84b8ac9cb99c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.53.0 -From fa209f059f1750824fb0258d6815d842a0dde04d Mon Sep 17 00:00:00 2001 +From 44c69ffc8396ae5e662ca549ec2c1db7daecacb9 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.53.0 -From 379d2ee8283e4a1778256aae1e05e5d0c271fe60 Mon Sep 17 00:00:00 2001 +From 0fd2c3dce177c7efe679fccdda88893fbb95ee5c Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb981f2..e03a1d8cdcb4 100644 -- 2.53.0 -From 45e1b6ea63062039adb5b7a1204510d69ed8aa10 Mon Sep 17 00:00:00 2001 +From 237556aa91bcd38f6e33770fcb539c247a8e347d Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 51dfa5c998..310279d159 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 1b73858484a66b2fdc5c1e22f1845e33afe0a22e Mon Sep 17 00:00:00 2001 +From 719242834658d260aa5df025b2c1e755af2f2c7c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 9fa321a95eb3..8914a922be2b 100644 +index d6138b2b633a..67094184c150 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -32,7 +32,7 @@ index 9fa321a95eb3..8914a922be2b 100644 #include -@@ -1171,6 +1172,17 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1175,6 +1176,17 @@ static void __init mp_config_acpi_legacy_irqs(void) } } @@ -50,7 +50,7 @@ index 9fa321a95eb3..8914a922be2b 100644 /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -@@ -1227,6 +1239,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) +@@ -1231,6 +1243,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, acpi_gbl_FADT.sci_interrupt); @@ -65,7 +65,7 @@ index 9fa321a95eb3..8914a922be2b 100644 -- 2.53.0 -From 20b7f69698f47be78cc922dd35f0942a3af8e911 Mon Sep 17 00:00:00 2001 +From af05a3b9893ecfc4e1b25e928cbb7101363c1fae Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,10 +80,10 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 8914a922be2b..c43d0a553867 100644 +index 67094184c150..9c1d2883e13e 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1178,12 +1178,19 @@ static void __init mp_config_acpi_legacy_irqs(void) static const struct dmi_system_id surface_quirk[] __initconst = { { diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 4868098785..72e8fa78c3 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 79a919027e012ab08f38a30d56de017469eabf61 Mon Sep 17 00:00:00 2001 +From 2d5ded4706b66cb55997b002dca0378dfdcc75f2 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index b06e7370ef..f8293c3083 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 4bf41a1c274e5a0bd33c2686b3d5ae676b31a876 Mon Sep 17 00:00:00 2001 +From 77ff006f6475aca9c238326ddff58b9a9e8e2d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000000..a171ea65672f -- 2.53.0 -From f558115833c7f39820424ffbf9b9b05fde7ef26f Mon Sep 17 00:00:00 2001 +From 1ec42aabd82bca6a0c0abfd13cb36c0f0e93328e Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 @@ -164,30 +164,30 @@ Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 Patchset: hid-surface --- - drivers/hid/hid-multitouch.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) + drivers/hid/hid-multitouch.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 1d245e998687..4d09710df6ba 100644 +index ee9c073af9b4..4f7603e56c10 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -83,6 +83,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_YOGABOOK9I BIT(24) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) - #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) -+#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(27) +@@ -84,6 +84,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(26) + #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(27) ++#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(28) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -244,6 +245,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_APPLE_TOUCHBAR 0x0114 +@@ -247,6 +248,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_YOGABOOK9I 0x0115 - #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0116 -+#define MT_CLS_SURFACE_TOUCHPAD 0x0117 + #define MT_CLS_EGALAX_P80H84 0x0116 + #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0117 ++#define MT_CLS_SURFACE_TOUCHPAD 0x0118 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -460,6 +462,10 @@ static const struct mt_class mt_classes[] = { +@@ -477,6 +479,10 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_WIN8_PTP_BUTTONS, .export_all_inputs = true }, @@ -198,7 +198,7 @@ index 1d245e998687..4d09710df6ba 100644 { } }; -@@ -2247,11 +2253,30 @@ static void mt_remove(struct hid_device *hdev) +@@ -2266,12 +2272,29 @@ static void mt_remove(struct hid_device *hdev) static void mt_on_hid_hw_open(struct hid_device *hdev) { @@ -222,14 +222,13 @@ index 1d245e998687..4d09710df6ba 100644 + * open/close hooks. Avoid mode switching on hw_open/hw_close for + * those devices. + */ -+ struct mt_device *td = hid_get_drvdata(hdev); + struct mt_device *td = hid_get_drvdata(hdev); + if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) + return; -+ - mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); - } -@@ -2697,6 +2722,11 @@ static const struct hid_device_id mt_devices[] = { + if (td->mtclass.quirks & MT_QUIRK_KEEP_LATENCY_ON_CLOSE) + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE); +@@ -2730,6 +2753,11 @@ static const struct hid_device_id mt_devices[] = { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_MICROSOFT, 0x09c0) }, From f9d67d3c7ae53d9368a0b74e138c0e5197f17487 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Tue, 10 Mar 2026 09:15:28 +0000 Subject: [PATCH 207/236] patches/v6.12: Update to v6.12.76 Generated 14 patches from linux-surface/kernel branch v6.12-surface Base version: v6.12.76 Branch: v6.12-surface Automatically generated patches using git-format-patchsets. --- patches/6.12/0001-secureboot.patch | 8 +-- patches/6.12/0002-surface3-oemb.patch | 4 +- patches/6.12/0003-mwifiex.patch | 16 +++--- patches/6.12/0004-ath10k.patch | 4 +- patches/6.12/0005-ipts.patch | 26 +++++----- patches/6.12/0006-ithc.patch | 12 ++--- patches/6.12/0007-surface-sam-over-hid.patch | 8 +-- patches/6.12/0008-surface-button.patch | 8 +-- patches/6.12/0009-surface-typecover.patch | 18 +++---- patches/6.12/0010-surface-shutdown.patch | 10 ++-- patches/6.12/0011-surface-gpe.patch | 4 +- patches/6.12/0012-cameras.patch | 54 ++++++++++---------- patches/6.12/0013-amd-gpio.patch | 8 +-- patches/6.12/0014-rtc.patch | 4 +- 14 files changed, 92 insertions(+), 92 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index 83d6908e54..4a6a08655c 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 8b1b5cd729869a871db085ccc43295634b09b09b Mon Sep 17 00:00:00 2001 +From 8d09002d4356483485c2580ca87a34b5f3d361c8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f433..a1bbedd98 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.52.0 +2.53.0 -From 8cf83548f5d2bb86f2d715927e42b39583a51153 Mon Sep 17 00:00:00 2001 +From 3f9e289841c6166e784ddae3bd16d7b8d3c2a488 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -108,5 +108,5 @@ index 85008ead2..48df5cfaf 100644 __setup("nohibernate", nohibernate_setup); +__setup("lockdown_hibernate", lockdown_hibernate_setup); -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index 1577da4b04..1edcaa2c56 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 9d6c8c98203766acc3fe944da6518fc68183f3b4 Mon Sep 17 00:00:00 2001 +From 888c10ccdb9f32091ab3ec94abcae8698c0557c1 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -97,5 +97,5 @@ index e4c3492a0..0b930c91b 100644 }; -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index fa9e0b231b..ebd2028f22 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From ba20c28fc68867c82de5787c33b729478c4843cf Mon Sep 17 00:00:00 2001 +From 4afbb30efe35caec71dc68fdc6dab46f67961cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -163,9 +163,9 @@ index d6ff964ae..5d30ae39d 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.52.0 +2.53.0 -From 1371b01d866820cc362e5f15fbb411df69fd06a5 Mon Sep 17 00:00:00 2001 +From da5716d67e5f0150bc07cf44da06fbb4d894069e Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -318,9 +318,9 @@ index 5d30ae39d..c14eb56eb 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.52.0 +2.53.0 -From 47c8c0aaf3d54f2d46a2469c0555e9569b2ce131 Mon Sep 17 00:00:00 2001 +From d2505cd7d32b5fc5b81382c4cbc1ce1393a57f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 490efe4d6..e15f99ee3 100644 +index 9d3236321..1670a26e5 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 490efe4d6..e15f99ee3 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4011,6 +4013,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4016,6 +4018,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -396,5 +396,5 @@ index 490efe4d6..e15f99ee3 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index 3c98f90458..f2176eb692 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From abdf26688b6c761b03e6a56d310504e63519544a Mon Sep 17 00:00:00 2001 +From 4a5651c06050c41d04ca79d4a47d4c6b771b3a7b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -116,5 +116,5 @@ index f9b51d98d..e04bac901 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index c303faabb1..9580eb3df2 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From 41c0348077f9cb3df9ae7109ad3c60afa373347c Mon Sep 17 00:00:00 2001 +From 23fbf7dcdeb0f2b04cbcdaa14a5b4b1b63d797b1 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -35,9 +35,9 @@ index 1e4edf896..61d1a8816 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.52.0 +2.53.0 -From f3802a79caac1ebbbf4780580982098c3beb38c7 Mon Sep 17 00:00:00 2001 +From 81895e560ee812ca707b39bb92de5fe4197c5815 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index c799cc67d..65adfc813 100644 +index d4f852f71..b76109d5d 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -40,6 +40,11 @@ @@ -91,7 +91,7 @@ index c799cc67d..65adfc813 100644 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -2066,6 +2073,9 @@ static int device_def_domain_type(struct device *dev) +@@ -2064,6 +2071,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index c799cc67d..65adfc813 100644 } return 0; -@@ -2364,6 +2374,9 @@ static int __init init_dmars(void) +@@ -2362,6 +2372,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index c799cc67d..65adfc813 100644 check_tylersburg_isoch(); /* -@@ -4691,6 +4704,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4684,6 +4697,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index c799cc67d..65adfc813 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -4729,6 +4754,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4722,6 +4747,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -142,9 +142,9 @@ index c799cc67d..65adfc813 100644 { if (risky_device(dev)) -- -2.52.0 +2.53.0 -From 4e08db916e493aa8197a2d7a29f23d439ece7abf Mon Sep 17 00:00:00 2001 +From 59ce30668370602d988bcb7b3717aa8c057bdd63 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,10 +211,10 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 95a4ede27..777d4619d 100644 +index f283f271d..4ce843941 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1388,4 +1388,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" +@@ -1389,4 +1389,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" source "drivers/hid/surface-hid/Kconfig" @@ -3237,5 +3237,5 @@ index 000000000..1f966b8b3 + +#endif /* IPTS_THREAD_H */ -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index 4453f31966..928198b6c3 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From 8a87179788582177344e3631f95e620104cb6e90 Mon Sep 17 00:00:00 2001 +From 673e3507f514ee0a6b63ab549f25d4507740f0cf Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -37,9 +37,9 @@ index 066e4cd6e..7b320d09d 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.52.0 +2.53.0 -From 081ec805c41368484ab34868192862970aa6fc8d Mon Sep 17 00:00:00 2001 +From 57ccc0251fe2fa2f424ead18d85832fbe4ceeca0 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,10 +86,10 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 777d4619d..d23316df4 100644 +index 4ce843941..b051b7068 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1390,4 +1390,6 @@ source "drivers/hid/surface-hid/Kconfig" +@@ -1391,4 +1391,6 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/ipts/Kconfig" @@ -2767,5 +2767,5 @@ index 000000000..aec320d4e +int ithc_reset(struct ithc *ithc); + -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index 17d191954c..3992272d7f 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 2f42938beeefa2b8f5773f2fc913c3f13e8a3aef Mon Sep 17 00:00:00 2001 +From 5a87dd60193963c9b28a9a58e27217f4fda90145 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -107,9 +107,9 @@ index f43067f67..1761ca30e 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.52.0 +2.53.0 -From 7aaf3683c5bd5b4d6648fdf9b62651150b4a7fd0 Mon Sep 17 00:00:00 2001 +From c04b0d4d8b4182b4302b0f03df1454eab9a792fa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -304,5 +304,5 @@ index 000000000..68db23773 +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index fc05e3b7ff..92df850eae 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From 4aa6a238f270308804dd79d4c08821c6f4ef72d3 Mon Sep 17 00:00:00 2001 +From af3f8f3a86740d0caa85e21b8d9a7c2b672906a9 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -73,9 +73,9 @@ index 5c5d407fe..4e1bfe90e 100644 /* -- -2.52.0 +2.53.0 -From f24443be9df034a21f1e4ed326c5bb2a5ea71d66 Mon Sep 17 00:00:00 2001 +From 6b7a4c7cd572993123287ab4f26f48c86ec0aa92 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -145,5 +145,5 @@ index 2755601f9..4240c98ca 100644 -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index cc4f521a04..94b5e331db 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From f9b45cc859c8379e5f12d738f414292146328bbe Mon Sep 17 00:00:00 2001 +From f08f3e9ed0542ec70e6f88b7b34b9e4168f020fd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -37,9 +37,9 @@ index 323a949bb..abc2cdecd 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.52.0 +2.53.0 -From af01dfc089d8eebc52c1828c885e43749316b54a Mon Sep 17 00:00:00 2001 +From ee707a758d5556280365f8af197a4ae9845a8d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index fcfc508d1..be4e0ebbc 100644 +index c3a914458..6ca3a3684 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -259,7 +259,7 @@ index fcfc508d1..be4e0ebbc 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2315,6 +2406,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2318,6 +2409,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -272,9 +272,9 @@ index fcfc508d1..be4e0ebbc 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.52.0 +2.53.0 -From 3874b935193791b6d142f64fb16071a77da3aa3e Mon Sep 17 00:00:00 2001 +From 0000b5cb26788fb71b8adfda9621f8f6afc83225 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index be4e0ebbc..a1df34afc 100644 +index 6ca3a3684..5c6ae7de7 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); @@ -571,5 +571,5 @@ index be4e0ebbc..a1df34afc 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index 0619bca16b..b97aa772be 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From f9dad7420d256b7fa2b822db3112eeb32066f704 Mon Sep 17 00:00:00 2001 +From 28467a583271770d1ea372a210a6b7ab50cf756e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index a00a2ce01..9754d756c 100644 +index 9846ab70c..38e674a1b 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,10 +37,10 @@ index a00a2ce01..9754d756c 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 18fa918b4..7a7613264 100644 +index 3d05ea35c..62bca34b0 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6338,3 +6338,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6365,3 +6365,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -93,5 +93,5 @@ index 242ee3843..96753fb66 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index cc91521d99..eb87ee1ce2 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From 35390087776e895b07f81f0af75cb21814b61e9e Mon Sep 17 00:00:00 2001 +From 9cef4331e693b13fc22809d5c628dda9b1ffcf24 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -47,5 +47,5 @@ index 62fd4004d..103fc4468 100644 .ident = "Surface Book 1", .matches = { -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index 7c16c8ef71..a47bd937cb 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From d0296461bb4c7a98b2a8fc0234c841a8c0adea30 Mon Sep 17 00:00:00 2001 +From 06a44113561fcebaf07821e7345c9b2ca7e783f1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -72,9 +72,9 @@ index ba98763ce..6021907ec 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.52.0 +2.53.0 -From 759e596605e96b0f66e3cda1cd757386c80fc2f6 Mon Sep 17 00:00:00 2001 +From 59e69a436cb8a5ea01ec61500a3815610d70648c Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 65adfc813..3dcabd6c5 100644 +index b76109d5d..06b2d4a85 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -45,6 +45,13 @@ @@ -132,7 +132,7 @@ index 65adfc813..3dcabd6c5 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -2074,6 +2083,9 @@ static int device_def_domain_type(struct device *dev) +@@ -2072,6 +2081,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index 65adfc813..3dcabd6c5 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2374,6 +2386,9 @@ static int __init init_dmars(void) +@@ -2372,6 +2384,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index 65adfc813..3dcabd6c5 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4704,6 +4719,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -4697,6 +4712,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index 65adfc813..3dcabd6c5 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4754,6 +4781,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4747,6 +4774,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -182,9 +182,9 @@ index 65adfc813..3dcabd6c5 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.52.0 +2.53.0 -From 1f9943aad6051f1db715ee97dadffd4c370c0114 Mon Sep 17 00:00:00 2001 +From 946fd9985e3144bf7cf8d9d11b96602d4189baab Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -219,9 +219,9 @@ index 81ac4c691..f453c9043 100644 return 0; -- -2.52.0 +2.53.0 -From f8915a8e39e48cc7812980b2a5e3921c4233e77e Mon Sep 17 00:00:00 2001 +From a438b4f3aca63561f32460cd0400e2d1548189fa Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -275,9 +275,9 @@ index 9e69ac9cf..d6003198a 100644 agpio, func, gpio_flags); if (ret) -- -2.52.0 +2.53.0 -From 24fe1fd44f8dce69d810881dd42f02db50ff82d2 Mon Sep 17 00:00:00 2001 +From e321ee96d9a8c08f02466f893ce80762bd349182 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -314,9 +314,9 @@ index 3226888d7..3bfe45b76 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.52.0 +2.53.0 -From ff6de3ab3241447e8076cf58462215901a5e625b Mon Sep 17 00:00:00 2001 +From 06d53e5e1461d11f3e2f38a41a37c0d0d6aeef4d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -335,10 +335,10 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index ee884a822..4f6bafd90 100644 +index 1c08bba9e..57a990d7d 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c -@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) +@@ -811,6 +811,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) INIT_LIST_HEAD(&sd->asc_list); @@ -365,9 +365,9 @@ index f19c8adf2..923ed1b5a 100644 if (ret < 0) goto out_cleanup; -- -2.52.0 +2.53.0 -From b928afccb5e17b202cfd8a55e960b0360a2dc0f7 Mon Sep 17 00:00:00 2001 +From 4ba987eb946b3cd99ff66e1d795fcfed122d48e9 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -406,9 +406,9 @@ index f453c9043..b8ad6b413 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.52.0 +2.53.0 -From 5230e237ca2ebcdcc24e1c43384ce3f76c515aa0 Mon Sep 17 00:00:00 2001 +From 6644e392bf583e2e9ecec68344a1b92b03d990d6 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -447,9 +447,9 @@ index 7807fa329..2d2abb25b 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.52.0 +2.53.0 -From 55d90afcd6b17799059e0a1c7ee7b37276a838ba Mon Sep 17 00:00:00 2001 +From 74032759acda3c94f308a238be0a16b3448271f0 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -698,9 +698,9 @@ index 000000000..35aeb5db8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.52.0 +2.53.0 -From 7040a2341b90a9d6792d2c5f763ed52a37e28318 Mon Sep 17 00:00:00 2001 +From ba2041730a467507a5882486d3a1e24dcf5dbee4 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -730,5 +730,5 @@ index c626ed845..0094cfda5 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index 2692692304..ef5d1b23c2 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From d2977155e31799f8789cbcef4fd860038361c158 Mon Sep 17 00:00:00 2001 +From bc7f7eb5a3275b16cad8ef38a4d52bcb01a2eaed Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -63,9 +63,9 @@ index 63adda8a1..00914222a 100644 mp_config_acpi_legacy_irqs(); -- -2.52.0 +2.53.0 -From 19369b388a100af758315e58bcb8a2f71488ebef Mon Sep 17 00:00:00 2001 +From 0535786e28e68e0ccf56d7f19964b55daeea9a46 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -105,5 +105,5 @@ index 00914222a..2b35bb58b 100644 }; -- -2.52.0 +2.53.0 diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index f89f71f413..ac7b7f3087 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From 73e1b53a85f74573a273a42358563a9748ee952c Mon Sep 17 00:00:00 2001 +From adecaa7f69aa83db889422a5e6ecb5a34f785842 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -106,5 +106,5 @@ index b75ceaab7..3dfcfd32d 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.52.0 +2.53.0 From 8901c202e2e58829b34f37d67ae98ccf5b760445 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Fri, 13 Mar 2026 10:06:24 +0000 Subject: [PATCH 208/236] patches/v6.18: Update to v6.18.17 Generated 16 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.17 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 10 +- patches/6.18/0002-surface3.patch | 12 +- patches/6.18/0003-mwifiex.patch | 20 +-- patches/6.18/0004-ath10k.patch | 4 +- patches/6.18/0005-ipts.patch | 68 +++++----- patches/6.18/0006-ithc.patch | 42 +++---- patches/6.18/0007-surface-sam.patch | 12 +- patches/6.18/0008-surface-sam-over-hid.patch | 12 +- patches/6.18/0009-surface-button.patch | 8 +- patches/6.18/0010-surface-typecover.patch | 12 +- patches/6.18/0011-surface-shutdown.patch | 12 +- patches/6.18/0012-surface-gpe.patch | 4 +- patches/6.18/0013-cameras.patch | 123 +++++++++++++++---- patches/6.18/0014-amd-gpio.patch | 8 +- patches/6.18/0015-rtc.patch | 4 +- patches/6.18/0016-hid-surface.patch | 37 +++--- 16 files changed, 233 insertions(+), 155 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 37a4c9befb..9eb4a97f79 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 61fc15e4514027eab8823c4ccf8d0a41c8216210 Mon Sep 17 00:00:00 2001 +From eba5e12b81b4d83ed0e11ecc6a6943f72d80a877 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -17,7 +17,7 @@ Patchset: secureboot 1 file changed, 4 insertions(+) diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index 9bea5a1e2c52..25848f886ad6 100644 +index 9bea5a1e2..25848f886 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -111,7 +111,11 @@ extra_header_fields: @@ -35,7 +35,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 -- 2.53.0 -From 27d5939b7a9289fef58883081d3281f6cb37bdd0 Mon Sep 17 00:00:00 2001 +From 619c5d07ffbbb58b4db1889d92810b617d80efca Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 6c42061ca20e..f7cb5669b5fb 100644 +index 6c42061ca..f7cb5669b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3342,6 +3342,11 @@ @@ -69,7 +69,7 @@ index 6c42061ca20e..f7cb5669b5fb 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 26e45f86b955..8ec46d4565a0 100644 +index 26e45f86b..8ec46d456 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -38,6 +38,7 @@ diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index 961ac9bfde..ff51f4d26b 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 2a24daccdb289b2937cc01a80be1889a14558665 Mon Sep 17 00:00:00 2001 +From 160f6904e9ad7e4a85ef37528386df468ed4a61b Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -40,7 +40,7 @@ Patchset: surface3 3 files changed, 24 insertions(+) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index 6c8fb7a4dde4..22797a53f4d8 100644 +index 6c8fb7a4d..22797a53f 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { @@ -58,7 +58,7 @@ index 6c8fb7a4dde4..22797a53f4d8 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 29a403526cd9..986f32132c3d 100644 +index 29a403526..986f32132 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3792,6 +3792,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -78,7 +78,7 @@ index 29a403526cd9..986f32132c3d 100644 /* * Match for the GPDwin which unfortunately uses somewhat diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0c28..0b930c91bccb 100644 +index e4c3492a0..0b930c91b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.53.0 -From 7a9c5e5d6ed881c6960966fad30834d365882797 Mon Sep 17 00:00:00 2001 +From 74659866d3a11f0effe87b52b20a8120a50d02fe Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -179,7 +179,7 @@ Patchset: surface3 1 file changed, 26 insertions(+) diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c -index 6074b7730e86..6aa3e1d6f160 100644 +index 6074b7730..6aa3e1d6f 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -25,6 +25,12 @@ diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index 832c99c739..c8667287bd 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 353b617522ef72033f62db75e05294493bbdde0a Mon Sep 17 00:00:00 2001 +From 6fef82bcc4edac718ab9f73f653be5bac8251009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -32,7 +32,7 @@ Patchset: mwifiex 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index a760de191fce..db9b203226a8 100644 +index a760de191..db9b20322 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) @@ -58,7 +58,7 @@ index a760de191fce..db9b203226a8 100644 mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 +index dd6d21f1d..f46b06f8d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -151,7 +151,7 @@ index dd6d21f1dbfd..f46b06f8d643 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 +index d6ff964ae..5d30ae39d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -4,6 +4,7 @@ @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.53.0 -From c66ba3aa77362a3173d0d23fc073a385caa375d4 Mon Sep 17 00:00:00 2001 +From a15f448edf557b3d022f0474d5b67b08399e0746 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -187,7 +187,7 @@ Patchset: mwifiex 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index db9b203226a8..ffd0c1fe9223 100644 +index db9b20322..ffd0c1fe9 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, @@ -212,7 +212,7 @@ index db9b203226a8..ffd0c1fe9223 100644 } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 +index f46b06f8d..99b024ecb 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -306,7 +306,7 @@ index f46b06f8d643..99b024ecbade 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 +index 5d30ae39d..c14eb56eb 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -5,6 +5,7 @@ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.53.0 -From 5585932011c9eea7f063af12a4bd60d3310b63ef Mon Sep 17 00:00:00 2001 +From 89de4725f7b15a3a27fbe851993c472889a304bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 7c7955afa8e8..c1c464bf33c6 100644 +index 7c7955afa..c1c464bf3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index cae53cbcea..60320fbe6b 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 6828bb428bbf9154633f460dbbeb1f0cb195f06d Mon Sep 17 00:00:00 2001 +From 3bcff82851b221fb8bddd3e085806afe4d32eb89 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 9ae3595fb698..b26a39c97998 100644 +index 9ae3595fb..b26a39c97 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -41,6 +41,9 @@ static bool fw_diag_log; diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 03e0fe128f..8ff8498853 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From aadb8ddca607fee65fb1aa22734667883907fbac Mon Sep 17 00:00:00 2001 +From 08a7818553d5e5f08c49233b7c26c1caa7010e5e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index fa30899a5fa2..a1864dcb713d 100644 +index fa30899a5..a1864dcb7 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index fa30899a5fa2..a1864dcb713d 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 2a6e569558b9..c19dfba542c1 100644 +index 2a6e56955..c19dfba54 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -37,7 +37,7 @@ index 2a6e569558b9..c19dfba542c1 100644 -- 2.53.0 -From 2826c58e75292d4ee0af2cc2c924ab0a224916b1 Mon Sep 17 00:00:00 2001 +From fbe131b36a06da8329f88913aa49b9979525e1d5 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 49e83c8566a3..a3e35c77da90 100644 +index 49e83c856..a3e35c77d 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -144,7 +144,7 @@ index 49e83c8566a3..a3e35c77da90 100644 -- 2.53.0 -From e8b9fe4bc745cb31da8c13853d562e02806aed13 Mon Sep 17 00:00:00 2001 +From 94d61f62aff23b9d8f14383a9bf5372999c2431c Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,7 +211,7 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 03ad8b5c29a4..c639bb1f6733 100644 +index 03ad8b5c2..c639bb1f6 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1440,6 +1440,8 @@ source "drivers/hid/surface-hid/Kconfig" @@ -224,7 +224,7 @@ index 03ad8b5c29a4..c639bb1f6733 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 361a7daedeb8..b73a1bbd3a1d 100644 +index 361a7daed..b73a1bbd3 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -176,3 +176,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -235,7 +235,7 @@ index 361a7daedeb8..b73a1bbd3a1d 100644 +obj-$(CONFIG_HID_IPTS) += ipts/ diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 000000000000..297401bd388d +index 000000000..297401bd3 --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -255,7 +255,7 @@ index 000000000000..297401bd388d + module will be called ipts. diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile new file mode 100644 -index 000000000000..883896f68e6a +index 000000000..883896f68 --- /dev/null +++ b/drivers/hid/ipts/Makefile @@ -0,0 +1,16 @@ @@ -277,7 +277,7 @@ index 000000000000..883896f68e6a +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 000000000000..63a4934bbc5f +index 000000000..63a4934bb --- /dev/null +++ b/drivers/hid/ipts/cmd.c @@ -0,0 +1,61 @@ @@ -344,7 +344,7 @@ index 000000000000..63a4934bbc5f +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 000000000000..2b4079075b64 +index 000000000..2b4079075 --- /dev/null +++ b/drivers/hid/ipts/cmd.h @@ -0,0 +1,60 @@ @@ -410,7 +410,7 @@ index 000000000000..2b4079075b64 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 000000000000..ba33259f1f7c +index 000000000..ba33259f1 --- /dev/null +++ b/drivers/hid/ipts/context.h @@ -0,0 +1,52 @@ @@ -468,7 +468,7 @@ index 000000000000..ba33259f1f7c +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 000000000000..5360842d260b +index 000000000..5360842d2 --- /dev/null +++ b/drivers/hid/ipts/control.c @@ -0,0 +1,486 @@ @@ -960,7 +960,7 @@ index 000000000000..5360842d260b +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 000000000000..26629c5144ed +index 000000000..26629c514 --- /dev/null +++ b/drivers/hid/ipts/control.h @@ -0,0 +1,126 @@ @@ -1092,7 +1092,7 @@ index 000000000000..26629c5144ed +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 000000000000..307438c7c80c +index 000000000..307438c7c --- /dev/null +++ b/drivers/hid/ipts/desc.h @@ -0,0 +1,80 @@ @@ -1178,7 +1178,7 @@ index 000000000000..307438c7c80c +#endif /* IPTS_DESC_H */ diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 000000000000..7b9f54388a9f +index 000000000..7b9f54388 --- /dev/null +++ b/drivers/hid/ipts/eds1.c @@ -0,0 +1,104 @@ @@ -1288,7 +1288,7 @@ index 000000000000..7b9f54388a9f +} diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h new file mode 100644 -index 000000000000..eeeb6575e3e8 +index 000000000..eeeb6575e --- /dev/null +++ b/drivers/hid/ipts/eds1.h @@ -0,0 +1,35 @@ @@ -1329,7 +1329,7 @@ index 000000000000..eeeb6575e3e8 + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c new file mode 100644 -index 000000000000..639940794615 +index 000000000..639940794 --- /dev/null +++ b/drivers/hid/ipts/eds2.c @@ -0,0 +1,145 @@ @@ -1480,7 +1480,7 @@ index 000000000000..639940794615 +} diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h new file mode 100644 -index 000000000000..064e3716907a +index 000000000..064e37169 --- /dev/null +++ b/drivers/hid/ipts/eds2.h @@ -0,0 +1,35 @@ @@ -1521,7 +1521,7 @@ index 000000000000..064e3716907a + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c new file mode 100644 -index 000000000000..e34a1a4f9fa7 +index 000000000..e34a1a4f9 --- /dev/null +++ b/drivers/hid/ipts/hid.c @@ -0,0 +1,225 @@ @@ -1752,7 +1752,7 @@ index 000000000000..e34a1a4f9fa7 +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 000000000000..1ebe77447903 +index 000000000..1ebe77447 --- /dev/null +++ b/drivers/hid/ipts/hid.h @@ -0,0 +1,24 @@ @@ -1782,7 +1782,7 @@ index 000000000000..1ebe77447903 +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 000000000000..fb5b5c13ee3e +index 000000000..fb5b5c13e --- /dev/null +++ b/drivers/hid/ipts/main.c @@ -0,0 +1,126 @@ @@ -1914,7 +1914,7 @@ index 000000000000..fb5b5c13ee3e +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 000000000000..1e0395ceae4a +index 000000000..1e0395cea --- /dev/null +++ b/drivers/hid/ipts/mei.c @@ -0,0 +1,188 @@ @@ -2108,7 +2108,7 @@ index 000000000000..1e0395ceae4a +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 000000000000..973bade6b0fd +index 000000000..973bade6b --- /dev/null +++ b/drivers/hid/ipts/mei.h @@ -0,0 +1,66 @@ @@ -2180,7 +2180,7 @@ index 000000000000..973bade6b0fd +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 000000000000..977724c728c3 +index 000000000..977724c72 --- /dev/null +++ b/drivers/hid/ipts/receiver.c @@ -0,0 +1,251 @@ @@ -2437,7 +2437,7 @@ index 000000000000..977724c728c3 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 000000000000..3de7da62d40c +index 000000000..3de7da62d --- /dev/null +++ b/drivers/hid/ipts/receiver.h @@ -0,0 +1,16 @@ @@ -2459,7 +2459,7 @@ index 000000000000..3de7da62d40c +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 000000000000..cc14653b2a9f +index 000000000..cc14653b2 --- /dev/null +++ b/drivers/hid/ipts/resources.c @@ -0,0 +1,131 @@ @@ -2596,7 +2596,7 @@ index 000000000000..cc14653b2a9f +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 000000000000..2068e13285f0 +index 000000000..2068e1328 --- /dev/null +++ b/drivers/hid/ipts/resources.h @@ -0,0 +1,41 @@ @@ -2643,7 +2643,7 @@ index 000000000000..2068e13285f0 +#endif /* IPTS_RESOURCES_H */ diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h new file mode 100644 -index 000000000000..e8dd98895a7e +index 000000000..e8dd98895 --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -2749,7 +2749,7 @@ index 000000000000..e8dd98895a7e +#endif /* IPTS_SPEC_DATA_H */ diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h new file mode 100644 -index 000000000000..41845f9d9025 +index 000000000..41845f9d9 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h @@ -0,0 +1,290 @@ @@ -3045,7 +3045,7 @@ index 000000000000..41845f9d9025 +#endif /* IPTS_SPEC_DEVICE_H */ diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h new file mode 100644 -index 000000000000..5a58d4a0a610 +index 000000000..5a58d4a0a --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h @@ -0,0 +1,34 @@ @@ -3085,7 +3085,7 @@ index 000000000000..5a58d4a0a610 +#endif /* IPTS_SPEC_HID_H */ diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c new file mode 100644 -index 000000000000..355e92bea26f +index 000000000..355e92bea --- /dev/null +++ b/drivers/hid/ipts/thread.c @@ -0,0 +1,84 @@ @@ -3175,7 +3175,7 @@ index 000000000000..355e92bea26f +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 000000000000..1f966b8b32c4 +index 000000000..1f966b8b3 --- /dev/null +++ b/drivers/hid/ipts/thread.h @@ -0,0 +1,59 @@ diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index 2c8f5aaadc..812cba5f23 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From 1b77daa3d810df158d892a3874f9ea3086bb988d Mon Sep 17 00:00:00 2001 +From d27f63695839ae3cc725c8d7666405dc0f7bb109 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,7 +10,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 8bcbfe3d9c72..c78806d35f2b 100644 +index 8bcbfe3d9..c78806d35 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) @@ -39,7 +39,7 @@ index 8bcbfe3d9c72..c78806d35f2b 100644 -- 2.53.0 -From 2182d874f3a525a08c81bc3ea2233a9340bdb7f2 Mon Sep 17 00:00:00 2001 +From 6a4e9c31e39e92ca1fea20632d41df7d67f666f3 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,7 +86,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index c639bb1f6733..b148be159c6b 100644 +index c639bb1f6..b148be159 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1442,6 +1442,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" @@ -99,7 +99,7 @@ index c639bb1f6733..b148be159c6b 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index b73a1bbd3a1d..3190ece25626 100644 +index b73a1bbd3..3190ece25 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -178,3 +178,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ @@ -109,7 +109,7 @@ index b73a1bbd3a1d..3190ece25626 100644 +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 000000000000..4937ba131297 +index 000000000..4937ba131 --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -121,7 +121,7 @@ index 000000000000..4937ba131297 + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 000000000000..ede713023609 +index 000000000..ede713023 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -139,7 +139,7 @@ index 000000000000..ede713023609 + module will be called ithc. diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c new file mode 100644 -index 000000000000..2d8c6afe9966 +index 000000000..2d8c6afe9 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,149 @@ @@ -294,7 +294,7 @@ index 000000000000..2d8c6afe9966 + diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h new file mode 100644 -index 000000000000..38c53d916bdb +index 000000000..38c53d916 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.h @@ -0,0 +1,7 @@ @@ -307,7 +307,7 @@ index 000000000000..38c53d916bdb + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 000000000000..bf4eab33062b +index 000000000..bf4eab330 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,312 @@ @@ -625,7 +625,7 @@ index 000000000000..bf4eab33062b + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 000000000000..1749a5819b3e +index 000000000..1749a5819 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,47 @@ @@ -678,7 +678,7 @@ index 000000000000..1749a5819b3e + diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c new file mode 100644 -index 000000000000..065646ab499e +index 000000000..065646ab4 --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.c @@ -0,0 +1,207 @@ @@ -891,7 +891,7 @@ index 000000000000..065646ab499e + diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h new file mode 100644 -index 000000000000..599eb912c8c8 +index 000000000..599eb912c --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.h @@ -0,0 +1,32 @@ @@ -929,7 +929,7 @@ index 000000000000..599eb912c8c8 + diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c new file mode 100644 -index 000000000000..8883987fb352 +index 000000000..8883987fb --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.c @@ -0,0 +1,254 @@ @@ -1189,7 +1189,7 @@ index 000000000000..8883987fb352 + diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h new file mode 100644 -index 000000000000..28d692462072 +index 000000000..28d692462 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.h @@ -0,0 +1,8 @@ @@ -1203,7 +1203,7 @@ index 000000000000..28d692462072 + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000000..094d878d671b +index 000000000..094d878d6 --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,438 @@ @@ -1647,7 +1647,7 @@ index 000000000000..094d878d671b + diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c new file mode 100644 -index 000000000000..e2d1690b8cf8 +index 000000000..e2d1690b8 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.c @@ -0,0 +1,607 @@ @@ -2260,7 +2260,7 @@ index 000000000000..e2d1690b8cf8 + diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h new file mode 100644 -index 000000000000..74d882f6b2f0 +index 000000000..74d882f6b --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.h @@ -0,0 +1,39 @@ @@ -2305,7 +2305,7 @@ index 000000000000..74d882f6b2f0 + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 000000000000..c0f13506af20 +index 000000000..c0f13506a --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,154 @@ @@ -2465,7 +2465,7 @@ index 000000000000..c0f13506af20 + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 000000000000..4f541fe533fa +index 000000000..4f541fe53 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,211 @@ @@ -2682,7 +2682,7 @@ index 000000000000..4f541fe533fa + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 000000000000..aec320d4e945 +index 000000000..aec320d4e --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,89 @@ diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index 7a56dd4804..049a351679 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 2374c2db81f54300a089ab54a33ad51e6c6c7ccb Mon Sep 17 00:00:00 2001 +From 3ba7fa6e5236b7ea4141f9f85d8636066d81dc0a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -14,7 +14,7 @@ Patchset: surface-sam create mode 100644 drivers/rtc/rtc-surface.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 2933c41c77c8..050eba74d8a2 100644 +index 2933c41c7..050eba74d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1399,6 +1399,13 @@ config RTC_DRV_NTXEC @@ -32,7 +32,7 @@ index 2933c41c77c8..050eba74d8a2 100644 config RTC_DRV_ASM9260 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile -index 8221bda6e6dc..8932df6e03ed 100644 +index 8221bda6e..8932df6e0 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -183,6 +183,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o @@ -45,7 +45,7 @@ index 8221bda6e6dc..8932df6e03ed 100644 obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c new file mode 100644 -index 000000000000..f6c17c4e98d5 +index 000000000..f6c17c4e9 --- /dev/null +++ b/drivers/rtc/rtc-surface.c @@ -0,0 +1,129 @@ @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.53.0 -From fffc105ff47eebcb30716b54b31577a16c8908f2 Mon Sep 17 00:00:00 2001 +From 58c3cb2fbdedd7c57ddb040217355ff718975fa5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -193,7 +193,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index a594d5fcfcfd..07b03aa4fa7f 100644 +index a594d5fcf..07b03aa4f 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 5abedee3d6..1845d26b53 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 09a3f9ef6f43e4810c6288655a9ef3880cff8f9a Mon Sep 17 00:00:00 2001 +From bffb18859041b06d2a02156b19f987103916d86b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,7 +55,7 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index ed90858a27b7..070c36637811 100644 +index ed90858a2..070c36637 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, @@ -109,7 +109,7 @@ index ed90858a27b7..070c36637811 100644 -- 2.53.0 -From 2b22b6f1c814aa1ad36bb0a7eff2b6f7baa6c8dd Mon Sep 17 00:00:00 2001 +From 0a73b819912d300caccd86b2a5d6aee5eb161f3e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -132,7 +132,7 @@ Patchset: surface-sam-over-hid create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index f775c6ca1ec1..2075e3852053 100644 +index f775c6ca1..2075e3852 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH @@ -150,7 +150,7 @@ index f775c6ca1ec1..2075e3852053 100644 tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 +index 533443309..7efcd0cdb 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o @@ -163,7 +163,7 @@ index 53344330939b..7efcd0cdb532 100644 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 000000000000..68db237734a1 +index 000000000..68db23773 --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c @@ -0,0 +1,136 @@ diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 9cc2711149..6559dda9cd 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From b1f6aead4130f4a4380145311d386671de8fb858 Mon Sep 17 00:00:00 2001 +From a7f4f1bfba7c8d96baadf1212006957c533f0d8a Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -20,7 +20,7 @@ Patchset: surface-button 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index b8cad415c62c..43b5d56383e3 100644 +index b8cad415c..43b5d5638 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.53.0 -From 88a4b033d52b0e708b81e3b5fbb55d0f74911aed Mon Sep 17 00:00:00 2001 +From b4ca6508297bbaf5ec174aae5abbb0f7ca46f611 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -96,7 +96,7 @@ Patchset: surface-button 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 +index 2755601f9..4240c98ca 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index e8a64bbaeb..5da817cd9d 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From d57e717c711d9d85f60b34787f041063e1e9e031 Mon Sep 17 00:00:00 2001 +From 3016f423ab0e10093a4ab502ca73830eb6760ea7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index c4d85089d19b..3d0d35c72189 100644 +index c4d85089d..3d0d35c72 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -39,7 +39,7 @@ index c4d85089d19b..3d0d35c72189 100644 -- 2.53.0 -From 23de036a4048527398fa6e8435a66b9968b818a9 Mon Sep 17 00:00:00 2001 +From 36fe9a8a785b46e63aadc92ff71ffa99d24069ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index af19e089b012..ab040ea64e28 100644 +index af19e089b..ab040ea64 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -274,7 +274,7 @@ index af19e089b012..ab040ea64e28 100644 -- 2.53.0 -From 9c94ebf4630a38563fc50f553e9293666943c538 Mon Sep 17 00:00:00 2001 +From 40bf0ca78f732f1041154d32180ddcb44571cad2 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,7 +303,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index ab040ea64e28..ee9c073af9b4 100644 +index ab040ea64..ee9c073af 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -83,6 +83,7 @@ MODULE_LICENSE("GPL"); diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index 20a2e4f82a..9e756f2745 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From f8b71f296d6df170fbccbe79edf6b7dbea1ad1a1 Mon Sep 17 00:00:00 2001 +From 5e53f226080bd78c28c436c087c7ba7743add4f7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index b4111c92c957..9c3db65ea09b 100644 +index b4111c92c..9c3db65ea 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,7 +37,7 @@ index b4111c92c957..9c3db65ea09b 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index d32a47e81fcf..68b9a0563731 100644 +index d32a47e81..68b9a0563 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6378,3 +6378,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) @@ -81,7 +81,7 @@ index d32a47e81fcf..68b9a0563731 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index 05aeee8c8844..006ea71cef1b 100644 +index 05aeee8c8..006ea71ce 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -488,6 +488,7 @@ struct pci_dev { @@ -95,7 +95,7 @@ index 05aeee8c8844..006ea71cef1b 100644 -- 2.53.0 -From 0db99235b7a2046ae056953165e2b32d7338a45b Mon Sep 17 00:00:00 2001 +From 12f8026700b5bc2d333b6da7528c31c82f379edb Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops @@ -108,7 +108,7 @@ Patchset: surface-shutdown 1 file changed, 13 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 68b9a0563731..848fd74a775f 100644 +index 68b9a0563..848fd74a7 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6397,6 +6397,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index fae3240a13..2d982bead9 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 0f90f3e26f3bb5459d6e294cf175416991d57a2c Mon Sep 17 00:00:00 2001 +From 766818fce3dbaefe80ab8c7b09bf83114d5d5d3e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -12,7 +12,7 @@ Patchset: surface-gpe 1 file changed, 17 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index b359413903b1..b4496db79f39 100644 +index b35941390..b4496db79 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index c12546ef45..1d0e529e91 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From 47b14611fae19a28fdf526bf965d399e83a578d8 Mon Sep 17 00:00:00 2001 +From d693daba3c12c84c53d38ab8e21e04963035734a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,7 +58,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index ef16d58b2949..a6bad2679a0c 100644 +index ef16d58b2..a6bad2679 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, @@ -74,7 +74,7 @@ index ef16d58b2949..a6bad2679a0c 100644 -- 2.53.0 -From b8ecbeb462117061326fd44bc4d55471c4e60aab Mon Sep 17 00:00:00 2001 +From c6ba60b1e0f18c27516419a7c611fbf7885e773c Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index a3e35c77da90..28567ba59de4 100644 +index a3e35c77d..28567ba59 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -184,7 +184,7 @@ index a3e35c77da90..28567ba59de4 100644 -- 2.53.0 -From 1d2553a63ea1cc01c78e54cdf2a8445a22bf0fa9 Mon Sep 17 00:00:00 2001 +From 86a9e06fbb44086759a3b055638c00d4a489b21d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -201,7 +201,7 @@ Patchset: cameras 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 0133405697dc..9e0763bdc758 100644 +index 013340569..9e0763bdc 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.53.0 -From d9cfd9e91d2c8bf63fbc3ded79deb9819ddc1936 Mon Sep 17 00:00:00 2001 +From 45343ef53c4105b306b313789527661a81c52d04 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -236,7 +236,7 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 27afc3fc0175..28b192c9a5ec 100644 +index 27afc3fc0..28b192c9a 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) @@ -260,7 +260,7 @@ index 27afc3fc0175..28b192c9a5ec 100644 -- 2.53.0 -From ee2b87e57a62013bfa325335222f4139429170d7 Mon Sep 17 00:00:00 2001 +From 32cea2dfe991c162cc0392db93ecee4d88a0ce76 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -279,7 +279,7 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index 1c08bba9ecb9..57a990d7dc84 100644 +index 1c08bba9e..57a990d7d 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -811,6 +811,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) @@ -294,7 +294,7 @@ index 1c08bba9ecb9..57a990d7dc84 100644 * No reference taken. The reference is held by the device (struct * v4l2_subdev.dev), and async sub-device does not exist independently diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index cb153ce42c45..f11b499e14bb 100644 +index cb153ce42..f11b499e1 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.53.0 -From c07f2a70d623be6cf766c41746bfcd5f274da66e Mon Sep 17 00:00:00 2001 +From 3ea45d9e1f9663a9b89962d6f99e9ed85e0fdbf9 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -327,7 +327,7 @@ Patchset: cameras 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 9e0763bdc758..0976b267972b 100644 +index 9e0763bdc..0976b2679 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.53.0 -From 32c23d5ec76cc6b256dd805dff4c84b8ac9cb99c Mon Sep 17 00:00:00 2001 +From 533c08f4994d9e3af95aaf417149646f2a12123c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -370,7 +370,7 @@ Patchset: cameras 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 +index 7807fa329..2d2abb25b 100644 --- a/include/linux/mfd/tps68470.h +++ b/include/linux/mfd/tps68470.h @@ -34,6 +34,7 @@ @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.53.0 -From 44c69ffc8396ae5e662ca549ec2c1db7daecacb9 Mon Sep 17 00:00:00 2001 +From 86d68e16a7aee5b4f0568b842a5b2b8a7907b916 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -416,7 +416,7 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 06e6291be11b..8f94924ef379 100644 +index 06e6291be..8f94924ef 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -1002,6 +1002,18 @@ config LEDS_TPS6105X @@ -439,7 +439,7 @@ index 06e6291be11b..8f94924ef379 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 9a0333ec1a86..4e1ca8fc9b41 100644 +index 9a0333ec1..4e1ca8fc9 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o @@ -452,7 +452,7 @@ index 9a0333ec1a86..4e1ca8fc9b41 100644 obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c new file mode 100644 -index 000000000000..35aeb5db89c8 +index 000000000..35aeb5db8 --- /dev/null +++ b/drivers/leds/leds-tps68470.c @@ -0,0 +1,185 @@ @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.53.0 -From 0fd2c3dce177c7efe679fccdda88893fbb95ee5c Mon Sep 17 00:00:00 2001 +From 38402757f9881b3afd7b1b33c9c0a66f9a80379f Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -660,7 +660,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index 032fbcb981f2..e03a1d8cdcb4 100644 +index 032fbcb98..e03a1d8cd 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c @@ -87,6 +87,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) @@ -676,7 +676,7 @@ index 032fbcb981f2..e03a1d8cdcb4 100644 -- 2.53.0 -From 237556aa91bcd38f6e33770fcb539c247a8e347d Mon Sep 17 00:00:00 2001 +From 652839ecc85fc2856d0a6c52498d61c04851c41f Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 @@ -693,7 +693,7 @@ Patchset: cameras 4 files changed, 184 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c -index 162b49046990..85cd0c98af03 100644 +index 162b49046..85cd0c98a 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -2,6 +2,7 @@ @@ -940,7 +940,7 @@ index 162b49046990..85cd0c98af03 100644 }, .probe = ov13858_probe, diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c -index d294477f9dd3..46bc6c5b7758 100644 +index d294477f9..46bc6c5b7 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -1396,6 +1396,7 @@ static const struct dev_pm_ops ov5693_pm_ops = { @@ -952,7 +952,7 @@ index d294477f9dd3..46bc6c5b7758 100644 }; MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c -index 4e579352ab2c..ac637207b644 100644 +index 4e579352a..ac637207b 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -60,6 +60,10 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { @@ -967,7 +967,7 @@ index 4e579352ab2c..ac637207b644 100644 IPU_SENSOR_CONFIG("INT3474", 1, 180000000), /* Omnivision OV5670 */ diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 1505fc3ef7a8..20962e8acb26 100644 +index 1505fc3ef..20962e8ac 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -229,6 +229,14 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 @@ -1017,3 +1017,74 @@ index 1505fc3ef7a8..20962e8acb26 100644 -- 2.53.0 +From 70b17884899e2d0abd5503efd9aff0ea05473233 Mon Sep 17 00:00:00 2001 +From: gabrielstedman +Date: Fri, 13 Mar 2026 08:52:07 +0000 +Subject: [PATCH] media: ipu-bridge: Add front camera rotation quirks for + Surface Pro 8 and 9 + +On the Surface Pro 8 and 9, camera rotation in `ssdb.degree` is `0` (no rotation) but should be `180`. Fix this with a quirk. + +Link: https://github.com/linux-surface/kernel/pull/160 +Patchset: cameras +--- + drivers/media/pci/intel/ipu-bridge.c | 29 ++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +index ac637207b..1ef31d655 100644 +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -98,6 +99,30 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { + IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000), + }; + ++static const struct dmi_system_id override_rotation[] = { ++ /* ++ * Systems on which rotation value need's to be overridden but ssdb->degree value is 0 (normal) ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ .driver_data = (void *)180, ++ }, ++ { ++ .ident = "Microsoft Surface Pro 8", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 8"), ++ }, ++ .driver_data = (void *)180, ++ }, ++ {} ++}; ++ ++ + static const struct ipu_property_names prop_names = { + .clock_frequency = "clock-frequency", + .rotation = "rotation", +@@ -248,6 +273,10 @@ static int ipu_bridge_read_acpi_buffer(struct acpi_device *adev, char *id, + static u32 ipu_bridge_parse_rotation(struct acpi_device *adev, + struct ipu_sensor_ssdb *ssdb) + { ++ const struct dmi_system_id *dmi_rotation; ++ dmi_rotation = dmi_first_match(override_rotation); ++ if (dmi_rotation && dmi_rotation->driver_data) ++ return (u32)(uintptr_t)dmi_rotation->driver_data; + switch (ssdb->degree) { + case IPU_SENSOR_ROTATION_NORMAL: + return 0; +-- +2.53.0 + diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 310279d159..4dbb0b5200 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 719242834658d260aa5df025b2c1e755af2f2c7c Mon Sep 17 00:00:00 2001 +From 8ff4b5a2af058663e766fc8edf8f24f8c21b007a Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index d6138b2b633a..67094184c150 100644 +index d6138b2b6..67094184c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -65,7 +65,7 @@ index d6138b2b633a..67094184c150 100644 -- 2.53.0 -From af05a3b9893ecfc4e1b25e928cbb7101363c1fae Mon Sep 17 00:00:00 2001 +From 0fb8ce91b92a1f4e90a29abb12ef276c3a1c9528 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,7 +80,7 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 67094184c150..9c1d2883e13e 100644 +index 67094184c..9c1d2883e 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1178,12 +1178,19 @@ static void __init mp_config_acpi_legacy_irqs(void) diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index 72e8fa78c3..f2dc0ff2c6 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 2d5ded4706b66cb55997b002dca0378dfdcc75f2 Mon Sep 17 00:00:00 2001 +From 4658081050d245b515333e5639b118e3fa6168dd Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 33418dd6768a..f94bbdc1de06 100644 +index 33418dd67..f94bbdc1d 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -433,6 +433,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index f8293c3083..6e005ebf4c 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 77ff006f6475aca9c238326ddff58b9a9e8e2d0d Mon Sep 17 00:00:00 2001 +From 8e9bab94eaad38d01e2df96a6a3888cfb727f488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -27,7 +27,7 @@ Patchset: hid-surface create mode 100644 drivers/hid/hid-surface.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index b148be159c6b..fd70eb54a0ea 100644 +index b148be159..fd70eb54a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1142,6 +1142,14 @@ config HID_SUNPLUS @@ -46,7 +46,7 @@ index b148be159c6b..fd70eb54a0ea 100644 tristate "Synaptics RMI4 device support" select RMI4_CORE diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 3190ece25626..4d2891879548 100644 +index 3190ece25..4d2891879 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -174,6 +174,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ @@ -59,7 +59,7 @@ index 3190ece25626..4d2891879548 100644 diff --git a/drivers/hid/hid-surface.c b/drivers/hid/hid-surface.c new file mode 100644 -index 000000000000..a171ea65672f +index 000000000..a171ea656 --- /dev/null +++ b/drivers/hid/hid-surface.c @@ -0,0 +1,90 @@ @@ -156,19 +156,22 @@ index 000000000000..a171ea65672f -- 2.53.0 -From 1ec42aabd82bca6a0c0abfd13cb36c0f0e93328e Mon Sep 17 00:00:00 2001 +From 79ae9d899ddc4ac988403fe349166dfd0dadc081 Mon Sep 17 00:00:00 2001 From: LegendaryFire -Date: Wed, 24 Dec 2025 00:54:44 -0800 +Date: Fri, 13 Mar 2026 10:16:37 +0100 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 touch pad +Note: Is this still required with MT_QUIRK_KEEP_LATENCY_ON_CLOSE now +being available? + Patchset: hid-surface --- - drivers/hid/hid-multitouch.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) + drivers/hid/hid-multitouch.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index ee9c073af9b4..4f7603e56c10 100644 +index ee9c073af..d6f2a286c 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -84,6 +84,7 @@ MODULE_LICENSE("GPL"); @@ -198,37 +201,41 @@ index ee9c073af9b4..4f7603e56c10 100644 { } }; -@@ -2266,12 +2272,29 @@ static void mt_remove(struct hid_device *hdev) +@@ -2266,6 +2272,17 @@ static void mt_remove(struct hid_device *hdev) static void mt_on_hid_hw_open(struct hid_device *hdev) { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* + * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck + * non-functional if we change touchpad reporting modes from the HID + * open/close hooks. Avoid mode switching on hw_open/hw_close for + * those devices. + */ -+ struct mt_device *td = hid_get_drvdata(hdev); + if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) + return; ++ mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); } - static void mt_on_hid_hw_close(struct hid_device *hdev) +@@ -2273,6 +2290,15 @@ static void mt_on_hid_hw_close(struct hid_device *hdev) { + struct mt_device *td = hid_get_drvdata(hdev); + + /* + * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck + * non-functional if we change touchpad reporting modes from the HID + * open/close hooks. Avoid mode switching on hw_open/hw_close for + * those devices. + */ - struct mt_device *td = hid_get_drvdata(hdev); + if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) + return; - ++ if (td->mtclass.quirks & MT_QUIRK_KEEP_LATENCY_ON_CLOSE) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE); -@@ -2730,6 +2753,11 @@ static const struct hid_device_id mt_devices[] = { + else +@@ -2730,6 +2756,11 @@ static const struct hid_device_id mt_devices[] = { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_MICROSOFT, 0x09c0) }, From ef091a60a180d4d799455f0673f907a4e170e688 Mon Sep 17 00:00:00 2001 From: Cornell Chin Date: Tue, 17 Feb 2026 09:31:30 -0500 Subject: [PATCH 209/236] Add patches for 6.19 Derived from latest 6.18 patches --- patches/6.19/0001-secureboot.patch | 112 + patches/6.19/0002-surface3.patch | 234 ++ patches/6.19/0003-mwifiex.patch | 400 +++ patches/6.19/0004-ath10k.patch | 120 + patches/6.19/0005-ipts.patch | 3243 ++++++++++++++++++ patches/6.19/0006-ithc.patch | 2780 +++++++++++++++ patches/6.19/0007-surface-sam.patch | 211 ++ patches/6.19/0008-surface-sam-over-hid.patch | 308 ++ patches/6.19/0009-surface-button.patch | 149 + patches/6.19/0010-surface-typecover.patch | 576 ++++ patches/6.19/0011-surface-shutdown.patch | 140 + patches/6.19/0012-surface-gpe.patch | 51 + patches/6.19/0013-cameras.patch | 1019 ++++++ patches/6.19/0014-amd-gpio.patch | 109 + patches/6.19/0015-rtc.patch | 111 + patches/6.19/0016-hid-surface.patch | 246 ++ patches/6.19/0017-powercap.patch | 30 + 17 files changed, 9839 insertions(+) create mode 100644 patches/6.19/0001-secureboot.patch create mode 100644 patches/6.19/0002-surface3.patch create mode 100644 patches/6.19/0003-mwifiex.patch create mode 100644 patches/6.19/0004-ath10k.patch create mode 100644 patches/6.19/0005-ipts.patch create mode 100644 patches/6.19/0006-ithc.patch create mode 100644 patches/6.19/0007-surface-sam.patch create mode 100644 patches/6.19/0008-surface-sam-over-hid.patch create mode 100644 patches/6.19/0009-surface-button.patch create mode 100644 patches/6.19/0010-surface-typecover.patch create mode 100644 patches/6.19/0011-surface-shutdown.patch create mode 100644 patches/6.19/0012-surface-gpe.patch create mode 100644 patches/6.19/0013-cameras.patch create mode 100644 patches/6.19/0014-amd-gpio.patch create mode 100644 patches/6.19/0015-rtc.patch create mode 100644 patches/6.19/0016-hid-surface.patch create mode 100644 patches/6.19/0017-powercap.patch diff --git a/patches/6.19/0001-secureboot.patch b/patches/6.19/0001-secureboot.patch new file mode 100644 index 0000000000..9d7e332c2d --- /dev/null +++ b/patches/6.19/0001-secureboot.patch @@ -0,0 +1,112 @@ +From 11f4a85c1156171c22e03216d13384bec651541e Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index 9bea5a1e2c52..25848f886ad6 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLLCHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.53.0 + +From 1e091139669d3d03f3abf3106ed2fabda98082bb Mon Sep 17 00:00:00 2001 +From: "J. Eduardo" +Date: Sun, 25 Aug 2024 14:17:45 +0200 +Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter + +This allows the user to tell the kernel that they know better (namely, +they secured their swap properly), and that it can enable hibernation. + +Signed-off-by: Kelvie Wong +Link: https://github.com/linux-surface/kernel/pull/158 +Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee +Patchset: secureboot +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + kernel/power/hibernate.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index aa0031108bc1..ca92d0e45220 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3500,6 +3500,11 @@ Kernel parameters + to extract confidential information from the kernel + are also disabled. + ++ lockdown_hibernate [HIBERNATION] ++ Enable hibernation even if lockdown is enabled. Enable this only if ++ your swap is encrypted and secured properly, as an attacker can ++ modify the kernel offline during hibernation. ++ + locktorture.acq_writer_lim= [KNL] + Set the time limit in jiffies for a lock + acquisition. Acquisitions exceeding this limit +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index af8d07bafe02..9e151554d5a0 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -38,6 +38,7 @@ + #include "power.h" + + ++static int lockdown_hibernate; + static int nocompress; + static int noresume; + static int nohibernate; +@@ -109,7 +110,7 @@ bool hibernation_in_progress(void) + bool hibernation_available(void) + { + return nohibernate == 0 && +- !security_locked_down(LOCKDOWN_HIBERNATION) && ++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) && + !secretmem_active() && !cxl_mem_active(); + } + +@@ -1493,6 +1494,12 @@ static int __init nohibernate_setup(char *str) + return 1; + } + ++static int __init lockdown_hibernate_setup(char *str) ++{ ++ lockdown_hibernate = 1; ++ return 1; ++} ++ + static const char * const comp_alg_enabled[] = { + #if IS_ENABLED(CONFIG_CRYPTO_LZO) + COMPRESSION_ALGO_LZO, +@@ -1550,3 +1557,4 @@ __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); + __setup("nohibernate", nohibernate_setup); ++__setup("lockdown_hibernate", lockdown_hibernate_setup); +-- +2.53.0 + diff --git a/patches/6.19/0002-surface3.patch b/patches/6.19/0002-surface3.patch new file mode 100644 index 0000000000..3392efd0d9 --- /dev/null +++ b/patches/6.19/0002-surface3.patch @@ -0,0 +1,234 @@ +From 15ab9b53834ba0ab25433ecfc02ee1659b2ff95b Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 18 Oct 2020 16:42:44 +0900 +Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI + table + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3 +--- + drivers/platform/surface/surface3-wmi.c | 7 +++++++ + sound/soc/codecs/rt5645.c | 9 +++++++++ + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index 6c8fb7a4dde4..22797a53f4d8 100644 +--- a/drivers/platform/surface/surface3-wmi.c ++++ b/drivers/platform/surface/surface3-wmi.c +@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index f7701b8d0d3c..0708c2fe8f61 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3793,6 +3793,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * Match for the GPDwin which unfortunately uses somewhat +diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +index e4c3492a0c28..0b930c91bccb 100644 +--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c ++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c +@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; + +-- +2.53.0 + +From c881590fdf25571ca9576ddb5fb1672092cd458a Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Fri, 6 Dec 2019 23:10:30 +0900 +Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by + default + +On Arch Linux kernel at least after 4.19, touch input is broken after suspend +(s2idle). + + kern :err : [ +0.203408] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + +On recent stable Arch Linux kernel (at least after 5.1), touch input will +crash after the first touch. + + kern :err : [ +0.203592] Surface3-spi spi-MSHW0037:00: SPI transfer timed out + kern :err : [ +0.000173] spi_master spi1: failed to transfer one message from queue + +I found on an affected system (Arch Linux kernel, etc.), the touchscreen +driver uses DMA mode by default. Then, we found some kernels with different +kernel config (5.1 kernel config from Jakeday [1] or Chromium OS kernel +chromeos-4.19 [2]) will use PIO mode by default and no such issues there. + +So, this commit disables DMA mode on the touchscreen driver side as a quick +workaround to avoid touch input crash. +We may need to properly set up DMA mode to use the touchscreen driver with +DMA mode. + +You can still switch DMA/PIO mode if you want: + + switch to DMA mode (maybe broken) + echo 1 | sudo tee /sys/module/surface3_spi/parameters/use_dma + back to PIO mode + echo 0 | sudo tee /sys/module/surface3_spi/parameters/use_dma + +Link to issue: https://github.com/jakeday/linux-surface/issues/596 + +References: +[1] https://github.com/jakeday/linux-surface/blob/master/configs/5.1/config +[2] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/chromeos-4.19 + +Tested on Arch Linux 5.4.1 with Surface 3, which will use DMA by default. +This commit made the driver use PIO by default and no touch input crash. +Also tested on chromeos-4.19 4.19.90 with Surface 3, which will use PIO by default +even without this commit. After this commit, it still uses PIO and confirmed +no functional changes regarding touch input. + +More details: + We can confirm which mode the touchscreen driver uses; first, enable + debug output: + + echo "file drivers/spi/spi-pxa2xx.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + echo "file drivers/input/touchscreen/surface3_spi.c +p" | sudo tee /sys/kernel/debug/dynamic_debug/control + + Then, try to make a touch input and see dmesg log + + (On Arch Linux kernel, uses DMA) + kern :debug : [ +0.006383] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, DMA + kern :debug : [ +0.000495] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 18 00 e4 01 00 04 1a 04 1a e3 0c e3 0c b0 00 + c5 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + + (On the kernels I referenced above, uses PIO) + kern :debug : [ +0.009260] Surface3-spi spi-MSHW0037:00: 7692307 Hz actual, PIO + kern :debug : [ +0.001105] Surface3-spi spi-MSHW0037:00: surface3_spi_irq_handler received + -> ff ff ff ff a5 5a e7 7e 01 d2 00 80 01 03 03 24 00 e4 01 00 58 0b 58 0b 83 12 83 12 26 01 + 95 01 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Note (2025-03-08): This patch was originally dropped due to the +comments in [3]. However, according to the commments in [4] it is still +required. + +[3]: https://github.com/linux-surface/kernel/commit/a3421c12bed0e46c28518bcb8c6b22f237c6dc7a +[4]: https://github.com/linux-surface/linux-surface/issues/1184 + +Patchset: surface3 +--- + drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c +index 6074b7730e86..6aa3e1d6f160 100644 +--- a/drivers/input/touchscreen/surface3_spi.c ++++ b/drivers/input/touchscreen/surface3_spi.c +@@ -25,6 +25,12 @@ + #define SURFACE3_REPORT_TOUCH 0xd2 + #define SURFACE3_REPORT_PEN 0x16 + ++bool use_dma = false; ++module_param(use_dma, bool, 0644); ++MODULE_PARM_DESC(use_dma, ++ "Disable DMA mode if you encounter touch input crash. " ++ "(default: false, disabled to avoid crash)"); ++ + struct surface3_ts_data { + struct spi_device *spi; + struct gpio_desc *gpiod_rst[2]; +@@ -317,6 +323,13 @@ static int surface3_spi_create_pen_input(struct surface3_ts_data *data) + return 0; + } + ++static bool surface3_spi_can_dma(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *tfr) ++{ ++ return use_dma; ++} ++ + static int surface3_spi_probe(struct spi_device *spi) + { + struct surface3_ts_data *data; +@@ -359,6 +372,19 @@ static int surface3_spi_probe(struct spi_device *spi) + if (error) + return error; + ++ /* ++ * Set up DMA ++ * ++ * TODO: Currently, touch input with DMA seems to be broken. ++ * On 4.19 LTS, touch input will crash after suspend. ++ * On recent stable kernel (at least after 5.1), touch input will crash after ++ * the first touch. No problem with PIO on those kernels. ++ * Maybe we need to configure DMA here. ++ * ++ * Link to issue: https://github.com/jakeday/linux-surface/issues/596 ++ */ ++ spi->controller->can_dma = surface3_spi_can_dma; ++ + return 0; + } + +-- +2.53.0 + diff --git a/patches/6.19/0003-mwifiex.patch b/patches/6.19/0003-mwifiex.patch new file mode 100644 index 0000000000..01d6126b41 --- /dev/null +++ b/patches/6.19/0003-mwifiex.patch @@ -0,0 +1,400 @@ +From 5c32be551d5e372447cc2f4faae21d20a07ae94e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Tue, 3 Nov 2020 13:28:04 +0100 +Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface + devices + +The most recent firmware of the 88W8897 card reports a hardcoded LTR +value to the system during initialization, probably as an (unsuccessful) +attempt of the developers to fix firmware crashes. This LTR value +prevents most of the Microsoft Surface devices from entering deep +powersaving states (either platform C-State 10 or S0ix state), because +the exit latency of that state would be higher than what the card can +tolerate. + +Turns out the card works just the same (including the firmware crashes) +no matter if that hardcoded LTR value is reported or not, so it's kind +of useless and only prevents us from saving power. + +To get rid of those hardcoded LTR reports, it's possible to reset the +PCI bridge device after initializing the cards firmware. I'm not exactly +sure why that works, maybe the power management subsystem of the PCH +resets its stored LTR values when doing a function level reset of the +bridge device. Doing the reset once after starting the wifi firmware +works very well, probably because the firmware only reports that LTR +value a single time during firmware startup. + +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index a760de191fce..db9b203226a8 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static void mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index dd6d21f1dbfd..f46b06f8d643 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE), + }, + {} + }; +@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index d6ff964aec5b..5d30ae39d65e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,7 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.53.0 + +From e4b75eaf26d9ffaa19c85875a8b6604783500e38 Mon Sep 17 00:00:00 2001 +From: Tsuchiya Yuto +Date: Sun, 4 Oct 2020 00:11:49 +0900 +Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: mwifiex +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index db9b203226a8..ffd0c1fe9223 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -418,6 +419,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f46b06f8d643..99b024ecbade 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, + .driver_data = (void *)(QUIRK_FW_RST_D3COLD | +- QUIRK_DO_FLR_ON_BRIDGE), ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); + if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) + dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5d30ae39d65e..c14eb56eb911 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -5,6 +5,7 @@ + + #define QUIRK_FW_RST_D3COLD BIT(0) + #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.53.0 + +From a15b4cd04c9904f36e0124d3175fa4daeeb1269b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 25 Mar 2021 11:33:02 +0100 +Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell + 88W8897 + +The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) +is used in a lot of Microsoft Surface devices, and all those devices +suffer from very low 2.4GHz wifi connection speeds while bluetooth is +enabled. The reason for that is that the default passive scanning +interval for Bluetooth Low Energy devices is quite high in Linux +(interval of 60 msec and scan window of 30 msec, see hci_core.c), and +the Marvell chip is known for its bad bt+wifi coexisting performance. + +So decrease that passive scan interval and make the scan window shorter +on this particular device to allow for spending more time transmitting +wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and +the new scan window is 6.25 msec (0xa * 0,625 msec). + +This change has a very large impact on the 2.4GHz wifi speeds and gets +it up to performance comparable with the Windows driver, which seems to +apply a similar quirk. + +The interval and window length were tested and found to work very well +with a lot of Bluetooth Low Energy devices, including the Surface Pen, a +Bluetooth Speaker and two modern Bluetooth headphones. All devices were +discovered immediately after turning them on. Even lower values were +also tested, but they introduced longer delays until devices get +discovered. + +Patchset: mwifiex +--- + drivers/bluetooth/btusb.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 80ccfa8fd982..093e17983eb7 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; + #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) + #define BTUSB_ACTIONS_SEMI BIT(27) + #define BTUSB_BARROT BIT(28) ++#define BTUSB_LOWER_LESCAN_INTERVAL BIT(29) + + static const struct usb_device_id btusb_table[] = { + /* Generic Bluetooth USB device */ +@@ -472,6 +473,7 @@ static const struct usb_device_id quirks_table[] = { + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, ++ { USB_DEVICE(0x1286, 0x204c), .driver_info = BTUSB_LOWER_LESCAN_INTERVAL }, + + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, +@@ -4229,6 +4231,19 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + ++ /* The Marvell 88W8897 combined wifi and bluetooth card is known for ++ * very bad bt+wifi coexisting performance. ++ * ++ * Decrease the passive BT Low Energy scan interval a bit ++ * (0x0190 * 0.625 msec = 250 msec) and make the scan window shorter ++ * (0x000a * 0,625 msec = 6.25 msec). This allows for significantly ++ * higher wifi throughput while passively scanning for BT LE devices. ++ */ ++ if (id->driver_info & BTUSB_LOWER_LESCAN_INTERVAL) { ++ hdev->le_scan_interval = 0x0190; ++ hdev->le_scan_window = 0x000a; ++ } ++ + if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && + (id->driver_info & BTUSB_MEDIATEK)) { + hdev->setup = btusb_mtk_setup; +-- +2.53.0 + diff --git a/patches/6.19/0004-ath10k.patch b/patches/6.19/0004-ath10k.patch new file mode 100644 index 0000000000..fc327230a9 --- /dev/null +++ b/patches/6.19/0004-ath10k.patch @@ -0,0 +1,120 @@ +From e5e36c49ec4ebd249eb220fa0028f57f1db3dc25 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Feb 2021 00:45:52 +0100 +Subject: [PATCH] ath10k: Add module parameters to override board files + +Some Surface devices, specifically the Surface Go and AMD version of the +Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better +with a different board file, as it seems that the firmeware included +upstream is buggy. + +As it is generally not a good idea to randomly overwrite files, let +alone doing so via packages, we add module parameters to override those +file names in the driver. This allows us to package/deploy the override +via a modprobe.d config. + +Signed-off-by: Maximilian Luz +Patchset: ath10k +--- + drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index 7c2939cbde5f..eb402a3a8c5f 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -41,6 +41,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -53,6 +56,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -62,6 +68,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -932,6 +941,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -946,6 +991,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); +-- +2.53.0 + diff --git a/patches/6.19/0005-ipts.patch b/patches/6.19/0005-ipts.patch new file mode 100644 index 0000000000..8258f7d10c --- /dev/null +++ b/patches/6.19/0005-ipts.patch @@ -0,0 +1,3243 @@ +From 6235e3f2891f0162cf07e78fd9a2d11f072d29e3 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Thu, 30 Jul 2020 13:21:53 +0200 +Subject: [PATCH] mei: me: Add Icelake device ID for iTouch + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index fa30899a5fa2..a1864dcb713d 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ + + #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 2a6e569558b9..c19dfba542c1 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +-- +2.53.0 + +From 36f2f146cc18cc0185c65637aa7f0d1689bcf4ee Mon Sep 17 00:00:00 2001 +From: Liban Hannan +Date: Tue, 12 Apr 2022 23:31:12 +0100 +Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS + +Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. +Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: + +DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr +0x104ea3000 [fault reason 0x06] PTE Read access is not set + +This is very similar to the bug described at: +https://bugs.launchpad.net/bugs/1958004 + +Fixed with the following patch which this patch basically copies: +https://launchpadlibrarian.net/586396847/43255ca.diff + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/iommu/intel/iommu.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 134302fbcd92..09d031bc873f 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -39,6 +39,11 @@ + #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) + #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) + ++#define IS_IPTS(pdev) ( \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x9D3E) || \ ++ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ++ ) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -202,12 +207,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + ++static int dmar_map_ipts = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; + +@@ -1401,6 +1408,9 @@ static int device_def_domain_type(struct device *dev) + + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; ++ ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; + } + + return 0; +@@ -1691,6 +1701,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); + + /* +@@ -3936,6 +3949,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Disabling IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); +@@ -3974,6 +3999,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); ++ + static void quirk_iommu_rwbf(struct pci_dev *dev) + { + if (risky_device(dev)) +-- +2.53.0 + +From af52eedf010166a262fae4b5fdd962226a5f0672 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:00:59 +0100 +Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus + +Based on linux-surface/intel-precise-touch@8abe268 + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 ++ + drivers/hid/ipts/cmd.c | 61 +++++ + drivers/hid/ipts/cmd.h | 60 ++++ + drivers/hid/ipts/context.h | 52 ++++ + drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++++++ + drivers/hid/ipts/desc.h | 80 ++++++ + drivers/hid/ipts/eds1.c | 104 +++++++ + drivers/hid/ipts/eds1.h | 35 +++ + drivers/hid/ipts/eds2.c | 145 ++++++++++ + drivers/hid/ipts/eds2.h | 35 +++ + drivers/hid/ipts/hid.c | 225 +++++++++++++++ + drivers/hid/ipts/hid.h | 24 ++ + drivers/hid/ipts/main.c | 126 +++++++++ + drivers/hid/ipts/mei.c | 188 +++++++++++++ + drivers/hid/ipts/mei.h | 66 +++++ + drivers/hid/ipts/receiver.c | 251 +++++++++++++++++ + drivers/hid/ipts/receiver.h | 16 ++ + drivers/hid/ipts/resources.c | 131 +++++++++ + drivers/hid/ipts/resources.h | 41 +++ + drivers/hid/ipts/spec-data.h | 100 +++++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++++++++++++ + drivers/hid/ipts/spec-hid.h | 34 +++ + drivers/hid/ipts/thread.c | 84 ++++++ + drivers/hid/ipts/thread.h | 59 ++++ + 28 files changed, 2853 insertions(+) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 920a64b66b25..314e3b0479be 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1442,6 +1442,8 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/intel-thc-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 361a7daedeb8..b73a1bbd3a1d 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -176,3 +176,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ +diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig +new file mode 100644 +index 000000000000..297401bd388d +--- /dev/null ++++ b/drivers/hid/ipts/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config HID_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ depends on INTEL_MEI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile +new file mode 100644 +index 000000000000..883896f68e6a +--- /dev/null ++++ b/drivers/hid/ipts/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_HID_IPTS) += ipts.o ++ipts-objs := cmd.o ++ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o ++ipts-objs += hid.o ++ipts-objs += main.o ++ipts-objs += mei.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += thread.o +diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c +new file mode 100644 +index 000000000000..63a4934bbc5f +--- /dev/null ++++ b/drivers/hid/ipts/cmd.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "mei.h" ++#include "spec-device.h" ++ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ /* ++ * In a response, the command code will have the most significant bit flipped to 1. ++ * If code is passed to ipts_mei_recv as is, no messages will be received. ++ */ ++ ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout); ++ if (ret < 0) ++ return ret; ++ ++ dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status); ++ ++ /* ++ * Some devices will always return this error. ++ * It is allowed to ignore it and to try continuing. ++ */ ++ if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL) ++ rsp->status = IPTS_STATUS_SUCCESS; ++ ++ return 0; ++} ++ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size) ++{ ++ struct ipts_command cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.cmd = code; ++ ++ if (data && size > 0) ++ memcpy(cmd.payload, data, size); ++ ++ dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size); ++ return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size); ++} +diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h +new file mode 100644 +index 000000000000..2b4079075b64 +--- /dev/null ++++ b/drivers/hid/ipts/cmd.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CMD_H ++#define IPTS_CMD_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++/* ++ * The default timeout for receiving responses ++ */ ++#define IPTS_CMD_DEFAULT_TIMEOUT 1000 ++ ++/** ++ * ipts_cmd_recv_timeout() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp, u64 timeout); ++ ++/** ++ * ipts_cmd_recv() - Receives a response to a command. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command / response. ++ * @rsp: The address that the received response will be copied to. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); ++} ++ ++/** ++ * ipts_cmd_send() - Executes a command on the device. ++ * @ipts: The IPTS driver context. ++ * @code: The type of the command to execute. ++ * @data: The payload containing parameters for the command. ++ * @size: The size of the payload. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size); ++ ++#endif /* IPTS_CMD_H */ +diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h +new file mode 100644 +index 000000000000..ba33259f1f7c +--- /dev/null ++++ b/drivers/hid/ipts/context.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTEXT_H ++#define IPTS_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mei.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++struct ipts_context { ++ struct device *dev; ++ struct ipts_mei mei; ++ ++ enum ipts_mode mode; ++ ++ /* ++ * Prevents concurrent GET_FEATURE reports. ++ */ ++ struct mutex feature_lock; ++ struct completion feature_event; ++ ++ /* ++ * These are not inside of struct ipts_resources ++ * because they don't own the memory they point to. ++ */ ++ struct ipts_buffer feature_report; ++ struct ipts_buffer descriptor; ++ ++ bool hid_active; ++ struct hid_device *hid; ++ ++ struct ipts_device_info info; ++ struct ipts_resources resources; ++ ++ struct ipts_thread receiver_loop; ++}; ++ ++#endif /* IPTS_CONTEXT_H */ +diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c +new file mode 100644 +index 000000000000..5360842d260b +--- /dev/null ++++ b/drivers/hid/ipts/control.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!info) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ memcpy(info, rsp.payload, sizeof(*info)); ++ return 0; ++} ++ ++static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ struct ipts_set_mode cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.mode = mode; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) ++{ ++ int i = 0; ++ int ret = 0; ++ struct ipts_mem_window cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); ++ cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); ++ cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); ++ cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address); ++ ++ cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address); ++ cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address); ++ ++ cmd.workqueue_size = IPTS_WORKQUEUE_SIZE; ++ cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++static int ipts_control_get_descriptor(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_data_header *header = NULL; ++ struct ipts_get_descriptor cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.descriptor.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size); ++ ++ cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address); ++ cmd.magic = 8; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ header = (struct ipts_data_header *)ipts->resources.descriptor.address; ++ ++ if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) { ++ ipts->descriptor.address = &header->data[8]; ++ ipts->descriptor.size = header->size - 8; ++ ++ return 0; ++ } ++ ++ return -ENODATA; ++} ++ ++int ipts_control_request_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_quiesce_io cmd = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd)); ++ if (ret) ++ dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_flush(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_request_data(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0); ++ if (ret) ++ dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown) ++{ ++ int ret = 0; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!shutdown) ++ ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0); ++ else ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret); ++ ++ return ret; ++ } ++ ++ /* ++ * During shutdown, it is possible that the sensor has already been disabled. ++ */ ++ if (rsp.status == IPTS_STATUS_SENSOR_DISABLED) ++ return 0; ++ ++ if (rsp.status == IPTS_STATUS_TIMEOUT) ++ return -EAGAIN; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) ++{ ++ int ret = 0; ++ struct ipts_feedback cmd = { 0 }; ++ struct ipts_response rsp = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ cmd.buffer = buffer; ++ ++ ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd)); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp); ++ if (ret) { ++ dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * We don't know what feedback data looks like so we are sending zeros. ++ * See also ipts_control_refill_buffer. ++ */ ++ if (rsp.status == IPTS_STATUS_INVALID_PARAMS) ++ return 0; ++ ++ if (rsp.status != IPTS_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status); ++ return -EBADR; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size) ++{ ++ struct ipts_feedback_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->resources.hid2me.address) ++ return -EFAULT; ++ ++ memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size); ++ header = (struct ipts_feedback_header *)ipts->resources.hid2me.address; ++ ++ header->cmd_type = cmd; ++ header->data_type = type; ++ header->size = size; ++ header->buffer = IPTS_HID2ME_BUFFER; ++ ++ if (size + sizeof(*header) > ipts->resources.hid2me.size) ++ return -EINVAL; ++ ++ if (data && size > 0) ++ memcpy(header->payload, data, size); ++ ++ return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ struct ipts_device_info info = { 0 }; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "Starting IPTS\n"); ++ ++ ret = ipts_control_get_device_info(ipts, &info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to get device info: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->info = info; ++ ++ ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate buffers: %d", ret); ++ return ret; ++ } ++ ++ dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds); ++ ++ /* ++ * Handle newer devices ++ */ ++ if (info.intf_eds > 1) { ++ /* ++ * Fetching the descriptor will only work on newer devices. ++ * For older devices, a fallback descriptor will be used. ++ */ ++ ret = ipts_control_get_descriptor(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Newer devices can be directly initialized in polling mode. ++ */ ++ ipts->mode = IPTS_MODE_POLL; ++ } ++ ++ ret = ipts_control_set_mode(ipts, ipts->mode); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set mode: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_set_mem_window(ipts, &ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to set memory window: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_receiver_start(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ return ret; ++ } ++ ++ ipts_hid_enable(ipts); ++ ++ ret = ipts_hid_init(ipts, info); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int _ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ipts_hid_disable(ipts); ++ dev_info(ipts->dev, "Stopping IPTS\n"); ++ ++ ret = ipts_receiver_stop(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_resources_free(&ipts->resources); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free resources: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_free(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to free HID device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ ret = _ipts_control_stop(ipts); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait a second to give the sensor time to fully shut down. ++ */ ++ msleep(1000); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h +new file mode 100644 +index 000000000000..26629c5144ed +--- /dev/null ++++ b/drivers/hid/ipts/control.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_CONTROL_H ++#define IPTS_CONTROL_H ++ ++#include ++ ++#include "context.h" ++#include "spec-data.h" ++#include "spec-device.h" ++ ++/** ++ * ipts_control_request_flush() - Stop the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Runs the command to stop the data flow on the device. ++ * All outstanding data needs to be acknowledged using feedback before the command will return. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Wait until data flow has been stopped. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_wait_flush(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_flush() - Notify the device that the driver can receive new data. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_request_data(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_wait_data() - Wait until new data is available. ++ * @ipts: The IPTS driver context. ++ * @block: Whether to block execution until data is available. ++ * ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. ++ */ ++int ipts_control_wait_data(struct ipts_context *ipts, bool block); ++ ++/** ++ * ipts_control_send_feedback() - Submits a feedback buffer to the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The ID of the buffer containing feedback data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); ++ ++/** ++ * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. ++ * @ipts: The IPTS driver context. ++ * @cmd: The command that will be run on the device. ++ * @type: The type of the payload that is sent to the device. ++ * @data: The payload of the feedback command. ++ * @size: The size of the payload. ++ * ++ * HID2ME feedback is a special type of feedback, because it allows interfacing with ++ * the HID API of the device at any moment, without requiring a buffer that has to ++ * be acknowledged. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, ++ enum ipts_feedback_data_type type, void *data, size_t size); ++ ++/** ++ * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer that has been processed and can be refilled. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer) ++{ ++ /* ++ * IPTS expects structured data in the feedback buffer matching the buffer that will be ++ * refilled. We don't know what that data looks like, so we just keep the buffer empty. ++ * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue. ++ * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling ++ * the buffers on some devices. ++ */ ++ ++ return ipts_control_send_feedback(ipts, buffer); ++} ++ ++/** ++ * ipts_control_start() - Initialized the device and starts the data flow. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_start(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_stop() - Stops the data flow and resets the device. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_stop(struct ipts_context *ipts); ++ ++/** ++ * ipts_control_restart() - Stops the device and starts it again. ++ * @ipts: The IPTS driver context. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_control_restart(struct ipts_context *ipts); ++ ++#endif /* IPTS_CONTROL_H */ +diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h +new file mode 100644 +index 000000000000..307438c7c80c +--- /dev/null ++++ b/drivers/hid/ipts/desc.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_DESC_H ++#define IPTS_DESC_H ++ ++#include ++ ++#define IPTS_HID_REPORT_SINGLETOUCH 64 ++#define IPTS_HID_REPORT_DATA 65 ++#define IPTS_HID_REPORT_SET_MODE 66 ++ ++#define IPTS_HID_REPORT_DATA_SIZE 7485 ++ ++/* ++ * HID descriptor for singletouch data. ++ * This descriptor should be present on all IPTS devices. ++ */ ++static const u8 ipts_singletouch_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x04, /* Usage (Touchscreen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x40, /* Report ID (64), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xA4, /* Push, */ ++ 0x55, 0x0E, /* Unit Exponent (14), */ ++ 0x65, 0x11, /* Unit (Centimeter), */ ++ 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0x74, 0x06, /* Physical Maximum (1652), */ ++ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0xC0, /* End Collection */ ++}; ++ ++/* ++ * Fallback HID descriptor for older devices that do not have ++ * the ability to query their HID descriptor. ++ */ ++static const u8 ipts_fallback_descriptor[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x41, /* Report ID (65), */ ++ 0x09, 0x56, /* Usage (Scan Time), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x61, /* Usage (Gesture Char Quality), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x96, 0x3D, 0x1D, /* Report Count (7485), */ ++ 0x81, 0x03, /* Input (Constant, Variable), */ ++ 0x85, 0x42, /* Report ID (66), */ ++ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ ++ 0x09, 0xC8, /* Usage (C8h), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0xB1, 0x02, /* Feature (Variable), */ ++ 0xC0, /* End Collection, */ ++}; ++ ++#endif /* IPTS_DESC_H */ +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +new file mode 100644 +index 000000000000..7b9f54388a9f +--- /dev/null ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds1.h" ++#include "spec-device.h" ++ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == mode) ++ return 0; ++ ++ ipts->mode = mode; ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; ++ ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000000..eeeb6575e3e8 +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +new file mode 100644 +index 000000000000..639940794615 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "eds2.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ ++ return 0; ++} ++ ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ mutex_lock(&ipts->feature_lock); ++ ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ ++ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); ++ reinit_completion(&ipts->feature_event); ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ goto out; ++ } ++ ++ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); ++ if (ret == 0) { ++ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); ++ ret = -EIO; ++ goto out; ++ } ++ ++ if (!ipts->feature_report.address) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ipts->feature_report.size > size) { ++ ret = -ETOOSMALL; ++ goto out; ++ } ++ ++ ret = ipts->feature_report.size; ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); ++ ++out: ++ mutex_unlock(&ipts->feature_lock); ++ return ret; ++} ++ ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ buffer[0] = report_id; ++ ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); ++ ++ return ret; ++} ++ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000000..064e3716907a +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type); +diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +new file mode 100644 +index 000000000000..e34a1a4f9fa7 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ u8 *buffer = NULL; ++ size_t size = 0; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); ++ else ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) ++{ ++ struct ipts_context *ipts = NULL; ++ ++ if (!hid) ++ return -ENODEV; ++ ++ ipts = hid->driver_data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } ++} ++ ++static struct hid_ll_driver ipts_hid_driver = { ++ .start = ipts_hid_start, ++ .stop = ipts_hid_stop, ++ .open = ipts_hid_start, ++ .close = ipts_hid_stop, ++ .parse = ipts_hid_parse, ++ .raw_request = ipts_hid_raw_request, ++}; ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) ++{ ++ u8 *temp = NULL; ++ struct ipts_hid_header *frame = NULL; ++ struct ipts_data_header *header = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return -ENODEV; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ header = (struct ipts_data_header *)ipts->resources.data[buffer].address; ++ ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ ++ if (!header) ++ return -EFAULT; ++ ++ if (header->size == 0) ++ return 0; ++ ++ if (header->type == IPTS_DATA_TYPE_HID) ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1); ++ ++ if (header->type == IPTS_DATA_TYPE_GET_FEATURES) { ++ ipts->feature_report.address = header->data; ++ ipts->feature_report.size = header->size; ++ ++ complete_all(&ipts->feature_event); ++ return 0; ++ } ++ ++ if (header->type != IPTS_DATA_TYPE_FRAME) ++ return 0; ++ ++ if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) ++ return -ERANGE; ++ ++ /* ++ * Synthesize a HID report matching the devices that natively send HID reports ++ */ ++ temp[0] = IPTS_HID_REPORT_DATA; ++ ++ frame = (struct ipts_hid_header *)&temp[3]; ++ frame->type = IPTS_HID_FRAME_TYPE_RAW; ++ frame->size = header->size + sizeof(*frame); ++ ++ memcpy(frame->data, header->data, header->size); ++ ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->hid) ++ return 0; ++ ++ ipts->hid = hid_allocate_device(); ++ if (IS_ERR(ipts->hid)) { ++ int err = PTR_ERR(ipts->hid); ++ ++ dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err); ++ return err; ++ } ++ ++ ipts->hid->driver_data = ipts; ++ ipts->hid->dev.parent = ipts->dev; ++ ipts->hid->ll_driver = &ipts_hid_driver; ++ ++ ipts->hid->vendor = info.vendor; ++ ipts->hid->product = info.product; ++ ipts->hid->group = HID_GROUP_GENERIC; ++ ++ snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, ++ info.product); ++ ++ ret = hid_add_device(ipts->hid); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to add HID device: %d\n", ret); ++ ipts_hid_free(ipts); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_hid_free(struct ipts_context *ipts) ++{ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!ipts->hid) ++ return 0; ++ ++ hid_destroy_device(ipts->hid); ++ ipts->hid = NULL; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h +new file mode 100644 +index 000000000000..1ebe77447903 +--- /dev/null ++++ b/drivers/hid/ipts/hid.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_HID_H ++#define IPTS_HID_H ++ ++#include ++ ++#include "context.h" ++#include "spec-device.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ ++int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); ++ ++int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); ++int ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* IPTS_HID_H */ +diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c +new file mode 100644 +index 000000000000..fb5b5c13ee3e +--- /dev/null ++++ b/drivers/hid/ipts/main.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "mei.h" ++#include "receiver.h" ++#include "spec-device.h" ++ ++/* ++ * The MEI client ID for IPTS functionality. ++ */ ++#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_set_dma_mask(struct mei_cl_device *cldev) ++{ ++ if (!cldev) ++ return -EFAULT; ++ ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) ++ return 0; ++ ++ return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); ++} ++ ++static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ ret = ipts_set_dma_mask(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ret = ipts_mei_init(&ipts->mei, cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret); ++ return ret; ++ } ++ ++ ipts->dev = &cldev->dev; ++ ipts->mode = IPTS_MODE_EVENT; ++ ++ mutex_init(&ipts->feature_lock); ++ init_completion(&ipts->feature_event); ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ret = ipts_control_start(ipts); ++ if (ret) { ++ dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ipts_remove(struct mei_cl_device *cldev) ++{ ++ int ret = 0; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ ++ ret = ipts_control_stop(ipts); ++ if (ret) ++ dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret); ++ ++ mei_cldev_disable(cldev); ++} ++ ++static struct mei_cl_device_id ipts_device_id_table[] = { ++ { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id_table); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id_table, ++ .name = "ipts", ++ .probe = ipts_probe, ++ .remove = ipts_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c +new file mode 100644 +index 000000000000..1e0395ceae4a +--- /dev/null ++++ b/drivers/hid/ipts/mei.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "mei.h" ++ ++static void locked_list_add(struct list_head *new, struct list_head *head, ++ struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_add(new, head); ++ up_write(lock); ++} ++ ++static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock) ++{ ++ down_write(lock); ++ list_del(entry); ++ up_write(lock); ++} ++ ++static void ipts_mei_incoming(struct mei_cl_device *cldev) ++{ ++ ssize_t ret = 0; ++ struct ipts_mei_message *entry = NULL; ++ struct ipts_context *ipts = NULL; ++ ++ if (!cldev) { ++ pr_err("MEI device is NULL!"); ++ return; ++ } ++ ++ ipts = mei_cldev_get_drvdata(cldev); ++ if (!ipts) { ++ pr_err("IPTS driver context is NULL!"); ++ return; ++ } ++ ++ entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ do { ++ ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp)); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) { ++ dev_err(ipts->dev, "Error while reading response: %ld\n", ret); ++ return; ++ } ++ ++ if (ret == 0) { ++ dev_err(ipts->dev, "Received empty response\n"); ++ return; ++ } ++ ++ locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock); ++ wake_up_all(&ipts->mei.message_queue); ++} ++ ++static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code, ++ struct ipts_response *rsp) ++{ ++ struct ipts_mei_message *entry = NULL; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!rsp) ++ return -EFAULT; ++ ++ down_read(&mei->message_lock); ++ ++ /* ++ * Iterate over the list of received messages, and check if there is one ++ * matching the requested command code. ++ */ ++ list_for_each_entry(entry, &mei->messages, list) { ++ if (entry->rsp.cmd == code) ++ break; ++ } ++ ++ up_read(&mei->message_lock); ++ ++ /* ++ * If entry is not the list head, this means that the loop above has been stopped early, ++ * and that we found a matching element. We drop the message from the list and return it. ++ */ ++ if (!list_entry_is_head(entry, &mei->messages, list)) { ++ locked_list_del(&entry->list, &mei->message_lock); ++ ++ *rsp = entry->rsp; ++ devm_kfree(&mei->cldev->dev, entry); ++ ++ return 0; ++ } ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ /* ++ * A timeout of 0 means check and return immideately. ++ */ ++ if (timeout == 0) ++ return ipts_mei_search(mei, code, rsp); ++ ++ /* ++ * A timeout of less than 0 means to wait forever. ++ */ ++ if (timeout < 0) { ++ wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0); ++ return 0; ++ } ++ ++ ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0, ++ msecs_to_jiffies(timeout)); ++ ++ if (ret > 0) ++ return 0; ++ ++ return -EAGAIN; ++} ++ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length) ++{ ++ int ret = 0; ++ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!mei->cldev) ++ return -EFAULT; ++ ++ if (!data) ++ return -EFAULT; ++ ++ do { ++ ret = mei_cldev_send(mei->cldev, (u8 *)data, length); ++ } while (ret == -EINTR); ++ ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev) ++{ ++ if (!mei) ++ return -EFAULT; ++ ++ if (!cldev) ++ return -EFAULT; ++ ++ mei->cldev = cldev; ++ ++ INIT_LIST_HEAD(&mei->messages); ++ init_waitqueue_head(&mei->message_queue); ++ init_rwsem(&mei->message_lock); ++ ++ mei_cldev_register_rx_cb(cldev, ipts_mei_incoming); ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h +new file mode 100644 +index 000000000000..973bade6b0fd +--- /dev/null ++++ b/drivers/hid/ipts/mei.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_MEI_H ++#define IPTS_MEI_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_mei_message { ++ struct list_head list; ++ struct ipts_response rsp; ++}; ++ ++struct ipts_mei { ++ struct mei_cl_device *cldev; ++ ++ struct list_head messages; ++ ++ wait_queue_head_t message_queue; ++ struct rw_semaphore message_lock; ++}; ++ ++/** ++ * ipts_mei_recv() - Receive data from a MEI device. ++ * @mei: The IPTS MEI device context. ++ * @code: The IPTS command code to look for. ++ * @rsp: The address that the received data will be copied to. ++ * @timeout: How many milliseconds the function will wait at most. ++ * ++ * A negative timeout means to wait forever. ++ * ++ * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received. ++ */ ++int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, ++ u64 timeout); ++ ++/** ++ * ipts_mei_send() - Send data to a MEI device. ++ * @ipts: The IPTS MEI device context. ++ * @data: The data to send. ++ * @size: The size of the data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); ++ ++/** ++ * ipts_mei_init() - Initialize the MEI device context. ++ * @mei: The MEI device context to initialize. ++ * @cldev: The MEI device the context will be bound to. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev); ++ ++#endif /* IPTS_MEI_H */ +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +new file mode 100644 +index 000000000000..977724c728c3 +--- /dev/null ++++ b/drivers/hid/ipts/receiver.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cmd.h" ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "receiver.h" ++#include "resources.h" ++#include "spec-device.h" ++#include "thread.h" ++ ++static void ipts_receiver_next_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ *doorbell = *doorbell + 1; ++} ++ ++static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts) ++{ ++ u32 *doorbell = (u32 *)ipts->resources.doorbell.address; ++ return *doorbell; ++} ++ ++static void ipts_receiver_backoff(time64_t last, u32 n) ++{ ++ /* ++ * If the last change was less than n seconds ago, ++ * sleep for a shorter period so that new data can be ++ * processed quickly. If there was no change for more than ++ * n seconds, sleep longer to avoid wasting CPU cycles. ++ */ ++ if (last + n > ktime_get_seconds()) ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); ++ else ++ msleep(200); ++} ++ ++static int ipts_receiver_event_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in event mode\n"); ++ ++ while (!ipts_thread_should_stop(thread)) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_control_wait_data(ipts, false); ++ if (ret == -EAGAIN) ++ break; ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ continue; ++ } ++ ++ buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS; ++ ipts_receiver_next_doorbell(ipts); ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ ret = ipts_control_request_data(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to request data: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ } ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ u32 buffer = 0; ++ ++ u32 doorbell = 0; ++ u32 lastdb = 0; ++ ++ struct ipts_context *ipts = NULL; ++ time64_t last = ktime_get_seconds(); ++ ++ if (!thread) ++ return -EFAULT; ++ ++ ipts = thread->data; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); ++ ++ while (true) { ++ if (ipts_thread_should_stop(thread)) { ++ ret = ipts_control_request_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to request flush: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ doorbell = ipts_receiver_current_doorbell(ipts); ++ ++ /* ++ * After filling up one of the data buffers, IPTS will increment ++ * the doorbell. The value of the doorbell stands for the *next* ++ * buffer that IPTS is going to fill. ++ */ ++ while (lastdb != doorbell) { ++ buffer = lastdb % IPTS_BUFFERS; ++ ++ ret = ipts_hid_input_data(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to process buffer: %d\n", ret); ++ ++ ret = ipts_control_refill_buffer(ipts, buffer); ++ if (ret) ++ dev_err(ipts->dev, "Failed to send feedback: %d\n", ret); ++ ++ last = ktime_get_seconds(); ++ lastdb++; ++ } ++ ++ if (ipts_thread_should_stop(thread)) ++ break; ++ ++ ipts_receiver_backoff(last, 5); ++ } ++ ++ ret = ipts_control_wait_data(ipts, true); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for data: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ ret = ipts_control_wait_flush(ipts); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret); ++ ++ if (ret != -EAGAIN) ++ return ret; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_start(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (ipts->mode == IPTS_MODE_EVENT) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, ++ "ipts_event"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_receiver_stop(struct ipts_context *ipts) ++{ ++ int ret = 0; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ ret = ipts_thread_stop(&ipts->receiver_loop); ++ if (ret) { ++ dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h +new file mode 100644 +index 000000000000..3de7da62d40c +--- /dev/null ++++ b/drivers/hid/ipts/receiver.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RECEIVER_H ++#define IPTS_RECEIVER_H ++ ++#include "context.h" ++ ++int ipts_receiver_start(struct ipts_context *ipts); ++int ipts_receiver_stop(struct ipts_context *ipts); ++ ++#endif /* IPTS_RECEIVER_H */ +diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c +new file mode 100644 +index 000000000000..cc14653b2a9f +--- /dev/null ++++ b/drivers/hid/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++ ++#include "desc.h" ++#include "resources.h" ++#include "spec-device.h" ++ ++static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size) ++{ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (buffer->address) ++ return 0; ++ ++ buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL); ++ ++ if (!buffer->address) ++ return -ENOMEM; ++ ++ buffer->size = size; ++ buffer->device = dev; ++ ++ return 0; ++} ++ ++static void ipts_resources_free_buffer(struct ipts_buffer *buffer) ++{ ++ if (!buffer->address) ++ return; ++ ++ dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address); ++ ++ buffer->address = NULL; ++ buffer->size = 0; ++ ++ buffer->dma_address = 0; ++ buffer->device = NULL; ++} ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs) ++{ ++ int ret = 0; ++ ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); ++ if (ret) ++ goto err; ++ } ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { ++ ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); ++ if (ret) ++ goto err; ++ } ++ ++ ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32)); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs); ++ if (ret) ++ goto err; ++ ++ ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8); ++ if (ret) ++ goto err; ++ ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ ++ ipts_resources_free(res); ++ return ret; ++} ++ ++int ipts_resources_free(struct ipts_resources *res) ++{ ++ int i = 0; ++ ++ if (!res) ++ return -EFAULT; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->data[i]); ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) ++ ipts_resources_free_buffer(&res->feedback[i]); ++ ++ ipts_resources_free_buffer(&res->doorbell); ++ ipts_resources_free_buffer(&res->workqueue); ++ ipts_resources_free_buffer(&res->hid2me); ++ ipts_resources_free_buffer(&res->descriptor); ++ ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ ++ return 0; ++} +diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h +new file mode 100644 +index 000000000000..2068e13285f0 +--- /dev/null ++++ b/drivers/hid/ipts/resources.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_RESOURCES_H ++#define IPTS_RESOURCES_H ++ ++#include ++#include ++ ++#include "spec-device.h" ++ ++struct ipts_buffer { ++ u8 *address; ++ size_t size; ++ ++ dma_addr_t dma_address; ++ struct device *device; ++}; ++ ++struct ipts_resources { ++ struct ipts_buffer data[IPTS_BUFFERS]; ++ struct ipts_buffer feedback[IPTS_BUFFERS]; ++ ++ struct ipts_buffer doorbell; ++ struct ipts_buffer workqueue; ++ struct ipts_buffer hid2me; ++ ++ struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; ++}; ++ ++int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); ++int ipts_resources_free(struct ipts_resources *res); ++ ++#endif /* IPTS_RESOURCES_H */ +diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h +new file mode 100644 +index 000000000000..e8dd98895a7e +--- /dev/null ++++ b/drivers/hid/ipts/spec-data.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DATA_H ++#define IPTS_SPEC_DATA_H ++ ++#include ++#include ++ ++/** ++ * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback. ++ */ ++enum ipts_feedback_cmd_type { ++ IPTS_FEEDBACK_CMD_TYPE_NONE = 0, ++ IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4, ++ IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5, ++ IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6, ++}; ++ ++/** ++ * enum ipts_feedback_data_type - Defines what data a feedback buffer contains. ++ * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback. ++ * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report. ++ * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report. ++ * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor. ++ */ ++enum ipts_feedback_data_type { ++ IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0, ++ IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1, ++ IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2, ++ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3, ++ IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4, ++}; ++ ++/** ++ * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer. ++ * @cmd_type: A command that should be executed on the sensor. ++ * @size: The size of the payload to be written. ++ * @buffer: The ID of the buffer that contains this feedback data. ++ * @protocol: The protocol version of the EDS. ++ * @data_type: The type of data that the buffer contains. ++ * @spi_offset: The offset at which to write the payload data to the sensor. ++ * @payload: Payload for the feedback command, or 0 if no payload is sent. ++ */ ++struct ipts_feedback_header { ++ enum ipts_feedback_cmd_type cmd_type; ++ u32 size; ++ u32 buffer; ++ u32 protocol; ++ enum ipts_feedback_data_type data_type; ++ u32 spi_offset; ++ u8 reserved[40]; ++ u8 payload[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback_header) == 64); ++ ++/** ++ * enum ipts_data_type - Defines what type of data a buffer contains. ++ * @IPTS_DATA_TYPE_FRAME: Raw data frame. ++ * @IPTS_DATA_TYPE_ERROR: Error data. ++ * @IPTS_DATA_TYPE_VENDOR: Vendor specific data. ++ * @IPTS_DATA_TYPE_HID: A HID report. ++ * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command. ++ */ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_FRAME = 0x00, ++ IPTS_DATA_TYPE_ERROR = 0x01, ++ IPTS_DATA_TYPE_VENDOR = 0x02, ++ IPTS_DATA_TYPE_HID = 0x03, ++ IPTS_DATA_TYPE_GET_FEATURES = 0x04, ++ IPTS_DATA_TYPE_DESCRIPTOR = 0x05, ++}; ++ ++/** ++ * struct ipts_data_header - Header that is prefixed to the data in a data buffer. ++ * @type: What data the buffer contains. ++ * @size: How much data the buffer contains. ++ * @buffer: Which buffer the data is in. ++ */ ++struct ipts_data_header { ++ enum ipts_data_type type; ++ u32 size; ++ u32 buffer; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data_header) == 64); ++ ++#endif /* IPTS_SPEC_DATA_H */ +diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h +new file mode 100644 +index 000000000000..41845f9d9025 +--- /dev/null ++++ b/drivers/hid/ipts/spec-device.h +@@ -0,0 +1,290 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2016 Intel Corporation ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_DEVICE_H ++#define IPTS_SPEC_DEVICE_H ++ ++#include ++#include ++ ++/* ++ * The amount of buffers that IPTS can use for data transfer. ++ */ ++#define IPTS_BUFFERS 16 ++ ++/* ++ * The buffer ID that is used for HID2ME feedback ++ */ ++#define IPTS_HID2ME_BUFFER IPTS_BUFFERS ++ ++/** ++ * enum ipts_command - Commands that can be sent to the IPTS hardware. ++ * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device. ++ * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in. ++ * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver. ++ * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver. ++ * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data. ++ * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled. ++ * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device. ++ * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state. ++ * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device. ++ */ ++enum ipts_command_code { ++ IPTS_CMD_GET_DEVICE_INFO = 0x01, ++ IPTS_CMD_SET_MODE = 0x02, ++ IPTS_CMD_SET_MEM_WINDOW = 0x03, ++ IPTS_CMD_QUIESCE_IO = 0x04, ++ IPTS_CMD_READY_FOR_DATA = 0x05, ++ IPTS_CMD_FEEDBACK = 0x06, ++ IPTS_CMD_CLEAR_MEM_WINDOW = 0x07, ++ IPTS_CMD_RESET_SENSOR = 0x0B, ++ IPTS_CMD_GET_DESCRIPTOR = 0x0F, ++}; ++ ++/** ++ * enum ipts_status - Possible status codes returned by the IPTS device. ++ * @IPTS_STATUS_SUCCESS: Operation completed successfully. ++ * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload. ++ * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address. ++ * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload. ++ * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set. ++ * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type. ++ * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. ++ * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation. ++ * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred. ++ * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized. ++ * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed. ++ * The host can ignore this error and attempt to continue. ++ * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver. ++ * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset. ++ * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete. ++ * @IPTS_STATUS_TIMEOUT: The operation timed out. ++ * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values. ++ * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence. ++ * Further progress is not possible. ++ * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence. ++ * The driver can attempt to continue. ++ * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities. ++ * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done. ++ */ ++enum ipts_status { ++ IPTS_STATUS_SUCCESS = 0x00, ++ IPTS_STATUS_INVALID_PARAMS = 0x01, ++ IPTS_STATUS_ACCESS_DENIED = 0x02, ++ IPTS_STATUS_CMD_SIZE_ERROR = 0x03, ++ IPTS_STATUS_NOT_READY = 0x04, ++ IPTS_STATUS_REQUEST_OUTSTANDING = 0x05, ++ IPTS_STATUS_NO_SENSOR_FOUND = 0x06, ++ IPTS_STATUS_OUT_OF_MEMORY = 0x07, ++ IPTS_STATUS_INTERNAL_ERROR = 0x08, ++ IPTS_STATUS_SENSOR_DISABLED = 0x09, ++ IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A, ++ IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B, ++ IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C, ++ IPTS_STATUS_RESET_FAILED = 0x0D, ++ IPTS_STATUS_TIMEOUT = 0x0E, ++ IPTS_STATUS_TEST_MODE_FAIL = 0x0F, ++ IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10, ++ IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11, ++ IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12, ++ IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13, ++}; ++ ++/** ++ * struct ipts_command - Message that is sent to the device for calling a command. ++ * @cmd: The command that will be called. ++ * @payload: Payload containing parameters for the called command. ++ */ ++struct ipts_command { ++ enum ipts_command_code cmd; ++ u8 payload[320]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_command) == 324); ++ ++/** ++ * enum ipts_mode - Configures what data the device produces and how its sent. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. ++ */ ++enum ipts_mode { ++ IPTS_MODE_EVENT = 0x00, ++ IPTS_MODE_POLL = 0x01, ++}; ++ ++/** ++ * struct ipts_set_mode - Payload for the SET_MODE command. ++ * @mode: Changes the mode that IPTS will operate in. ++ */ ++struct ipts_set_mode { ++ enum ipts_mode mode; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode) == 16); ++ ++#define IPTS_WORKQUEUE_SIZE 8192 ++#define IPTS_WORKQUEUE_ITEM_SIZE 16 ++ ++/** ++ * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command. ++ * @data_addr_lower: Lower 32 bits of the data buffer addresses. ++ * @data_addr_upper: Upper 32 bits of the data buffer addresses. ++ * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address. ++ * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address. ++ * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address. ++ * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address. ++ * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses. ++ * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses. ++ * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address. ++ * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address. ++ * @hid2me_size: Size of the hid2me feedback buffer. ++ * @workqueue_item_size: Magic value. Must be 16. ++ * @workqueue_size: Magic value. Must be 8192. ++ * ++ * The workqueue related items in this struct are required for using ++ * GuC submission with binary processing firmware. Since this driver does ++ * not use GuC submission and instead exports raw data to userspace, these ++ * items are not actually used, but they need to be allocated and passed ++ * to the device, otherwise initialization will fail. ++ */ ++struct ipts_mem_window { ++ u32 data_addr_lower[IPTS_BUFFERS]; ++ u32 data_addr_upper[IPTS_BUFFERS]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_addr_lower[IPTS_BUFFERS]; ++ u32 feedback_addr_upper[IPTS_BUFFERS]; ++ u32 hid2me_addr_lower; ++ u32 hid2me_addr_upper; ++ u32 hid2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_mem_window) == 320); ++ ++/** ++ * struct ipts_quiesce_io - Payload for the QUIESCE_IO command. ++ */ ++struct ipts_quiesce_io { ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_quiesce_io) == 12); ++ ++/** ++ * struct ipts_feedback - Payload for the FEEDBACK command. ++ * @buffer: The buffer that the device should refill. ++ */ ++struct ipts_feedback { ++ u32 buffer; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 16); ++ ++/** ++ * enum ipts_reset_type - Possible ways of resetting the device. ++ * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin. ++ * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command. ++ */ ++enum ipts_reset_type { ++ IPTS_RESET_TYPE_HARD = 0x00, ++ IPTS_RESET_TYPE_SOFT = 0x01, ++}; ++ ++/** ++ * struct ipts_reset - Payload for the RESET_SENSOR command. ++ * @type: How the device should get reset. ++ */ ++struct ipts_reset_sensor { ++ enum ipts_reset_type type; ++ u8 reserved[4]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_reset_sensor) == 8); ++ ++/** ++ * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command. ++ * @addr_lower: The lower 32 bits of the descriptor buffer address. ++ * @addr_upper: The upper 32 bits of the descriptor buffer address. ++ * @magic: A magic value. Must be 8. ++ */ ++struct ipts_get_descriptor { ++ u32 addr_lower; ++ u32 addr_upper; ++ u32 magic; ++ u8 reserved[12]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_get_descriptor) == 24); ++ ++/* ++ * The type of a response is indicated by a ++ * command code, with the most significant bit flipped to 1. ++ */ ++#define IPTS_RSP_BIT BIT(31) ++ ++/** ++ * struct ipts_response - Data returned from the device in response to a command. ++ * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1). ++ * @status: The return code of the command. ++ * @payload: The data that was produced by the command. ++ */ ++struct ipts_response { ++ enum ipts_command_code cmd; ++ enum ipts_status status; ++ u8 payload[80]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_response) == 88); ++ ++/** ++ * struct ipts_device_info - Vendor information of the IPTS device. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. ++ */ ++struct ipts_device_info { ++ u16 vendor; ++ u16 product; ++ u32 hw_version; ++ u32 fw_version; ++ u32 data_size; ++ u32 feedback_size; ++ enum ipts_mode mode; ++ u8 max_contacts; ++ u8 reserved1[3]; ++ u8 sensor_min_eds; ++ u8 sensor_maj_eds; ++ u8 me_min_eds; ++ u8 me_maj_eds; ++ u8 intf_eds; ++ u8 reserved2[11]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++ ++#endif /* IPTS_SPEC_DEVICE_H */ +diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h +new file mode 100644 +index 000000000000..5a58d4a0a610 +--- /dev/null ++++ b/drivers/hid/ipts/spec-hid.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2020-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_SPEC_HID_H ++#define IPTS_SPEC_HID_H ++ ++#include ++#include ++ ++/* ++ * Made-up type for passing raw IPTS data in a HID report. ++ */ ++#define IPTS_HID_FRAME_TYPE_RAW 0xEE ++ ++/** ++ * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report. ++ * @size: Size of the data inside the report, including this header. ++ * @type: What type of data does this report contain. ++ */ ++struct ipts_hid_header { ++ u32 size; ++ u8 reserved1; ++ u8 type; ++ u8 reserved2; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_hid_header) == 7); ++ ++#endif /* IPTS_SPEC_HID_H */ +diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c +new file mode 100644 +index 000000000000..355e92bea26f +--- /dev/null ++++ b/drivers/hid/ipts/thread.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "thread.h" ++ ++bool ipts_thread_should_stop(struct ipts_thread *thread) ++{ ++ if (!thread) ++ return false; ++ ++ return READ_ONCE(thread->should_stop); ++} ++ ++static int ipts_thread_runner(void *data) ++{ ++ int ret = 0; ++ struct ipts_thread *thread = data; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->threadfn) ++ return -EFAULT; ++ ++ ret = thread->threadfn(thread); ++ complete_all(&thread->done); ++ ++ return ret; ++} ++ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char *name) ++{ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!threadfn) ++ return -EFAULT; ++ ++ init_completion(&thread->done); ++ ++ thread->data = data; ++ thread->should_stop = false; ++ thread->threadfn = threadfn; ++ ++ thread->thread = kthread_run(ipts_thread_runner, thread, name); ++ return PTR_ERR_OR_ZERO(thread->thread); ++} ++ ++int ipts_thread_stop(struct ipts_thread *thread) ++{ ++ int ret = 0; ++ ++ if (!thread) ++ return -EFAULT; ++ ++ if (!thread->thread) ++ return 0; ++ ++ WRITE_ONCE(thread->should_stop, true); ++ ++ /* ++ * Make sure that the write has gone through before waiting. ++ */ ++ wmb(); ++ ++ wait_for_completion(&thread->done); ++ ret = kthread_stop(thread->thread); ++ ++ thread->thread = NULL; ++ thread->data = NULL; ++ thread->threadfn = NULL; ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h +new file mode 100644 +index 000000000000..1f966b8b32c4 +--- /dev/null ++++ b/drivers/hid/ipts/thread.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#ifndef IPTS_THREAD_H ++#define IPTS_THREAD_H ++ ++#include ++#include ++#include ++ ++/* ++ * This wrapper over kthread is necessary, because calling kthread_stop makes it impossible ++ * to issue MEI commands from that thread while it shuts itself down. By using a custom ++ * boolean variable and a completion object, we can call kthread_stop only when the thread ++ * already finished all of its work and has returned. ++ */ ++struct ipts_thread { ++ struct task_struct *thread; ++ ++ bool should_stop; ++ struct completion done; ++ ++ void *data; ++ int (*threadfn)(struct ipts_thread *thread); ++}; ++ ++/** ++ * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. ++ * @thread: The current thread. ++ * ++ * Returns: true if the thread should stop, false if not. ++ */ ++bool ipts_thread_should_stop(struct ipts_thread *thread); ++ ++/** ++ * ipts_thread_start() - Starts an IPTS thread. ++ * @thread: The thread to initialize and start. ++ * @threadfn: The function to execute. ++ * @data: An argument that will be passed to threadfn. ++ * @name: The name of the new thread. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), ++ void *data, const char name[]); ++ ++/** ++ * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. ++ * @thread: The thread that should stop. ++ * ++ * Returns: The return value of the thread function. ++ */ ++int ipts_thread_stop(struct ipts_thread *thread); ++ ++#endif /* IPTS_THREAD_H */ +-- +2.53.0 + diff --git a/patches/6.19/0006-ithc.patch b/patches/6.19/0006-ithc.patch new file mode 100644 index 0000000000..c3bf0ba836 --- /dev/null +++ b/patches/6.19/0006-ithc.patch @@ -0,0 +1,2780 @@ +From 703eeaea6536d65c01c092e5f844a784f2d18df5 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Sun, 11 Dec 2022 12:03:38 +0100 +Subject: [PATCH] iommu: intel: Disable source id verification for ITHC + +Signed-off-by: Dorian Stoll +Patchset: ithc +--- + drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 8bcbfe3d9c72..c78806d35f2b 100644 +--- a/drivers/iommu/intel/irq_remapping.c ++++ b/drivers/iommu/intel/irq_remapping.c +@@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); + ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * DMA alias provides us with a PCI device and alias. The only case + * where the it will return an alias on a different bus than the +-- +2.53.0 + +From 063f50f47ef7f0a0d4466f70b3450dc8335f5f24 Mon Sep 17 00:00:00 2001 +From: quo +Date: Sun, 11 Dec 2022 12:10:54 +0100 +Subject: [PATCH] hid: Add support for Intel Touch Host Controller + +Based on quo/ithc-linux@34539af4726d. + +Signed-off-by: Maximilian Stoll +Patchset: ithc +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 1 + + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 149 ++++++++ + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 312 ++++++++++++++++ + drivers/hid/ithc/ithc-dma.h | 47 +++ + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 254 +++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 438 ++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 ++ + drivers/hid/ithc/ithc-regs.c | 154 ++++++++ + drivers/hid/ithc/ithc-regs.h | 211 +++++++++++ + drivers/hid/ithc/ithc.h | 89 +++++ + 18 files changed, 2575 insertions(+) + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 314e3b0479be..59d597b4effd 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1444,6 +1444,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" + + source "drivers/hid/ipts/Kconfig" + ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID + + # USB support may be used with HID disabled +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index b73a1bbd3a1d..3190ece25626 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -178,3 +178,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + + obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +new file mode 100644 +index 000000000000..4937ba131297 +--- /dev/null ++++ b/drivers/hid/ithc/Kbuild +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_HID_ITHC) := ithc.o ++ ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o ++ ++ccflags-y := -std=gnu11 -Wno-declaration-after-statement ++ +diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig +new file mode 100644 +index 000000000000..ede713023609 +--- /dev/null ++++ b/drivers/hid/ithc/Kconfig +@@ -0,0 +1,12 @@ ++config HID_ITHC ++ tristate "Intel Touch Host Controller" ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Touch Host Controller (ITHC / IPTS) technology. ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ithc. +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +new file mode 100644 +index 000000000000..2d8c6afe9966 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++void ithc_log_regs(struct ithc *ithc) ++{ ++ if (!ithc->prev_regs) ++ return; ++ u32 __iomem *cur = (__iomem void *)ithc->regs; ++ u32 *prev = (void *)ithc->prev_regs; ++ for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) { ++ u32 x = readl(cur + i); ++ if (x != prev[i]) { ++ pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x); ++ prev[i] = x; ++ } ++ } ++} ++ ++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, ++ loff_t *offset) ++{ ++ // Debug commands consist of a single letter followed by a list of numbers (decimal or ++ // hexadecimal, space-separated). ++ struct ithc *ithc = file_inode(f)->i_private; ++ char cmd[256]; ++ if (!ithc || !ithc->pci) ++ return -ENODEV; ++ if (!len) ++ return -EINVAL; ++ if (len >= sizeof(cmd)) ++ return -EINVAL; ++ if (copy_from_user(cmd, buf, len)) ++ return -EFAULT; ++ cmd[len] = 0; ++ if (cmd[len-1] == '\n') ++ cmd[len-1] = 0; ++ pci_info(ithc->pci, "debug command: %s\n", cmd); ++ ++ // Parse the list of arguments into a u32 array. ++ u32 n = 0; ++ const char *s = cmd + 1; ++ u32 a[32]; ++ while (*s && *s != '\n') { ++ if (n >= ARRAY_SIZE(a)) ++ return -EINVAL; ++ if (*s++ != ' ') ++ return -EINVAL; ++ char *e; ++ a[n++] = simple_strtoul(s, &e, 0); ++ if (e == s) ++ return -EINVAL; ++ s = e; ++ } ++ ithc_log_regs(ithc); ++ ++ // Execute the command. ++ switch (cmd[0]) { ++ case 'x': // reset ++ ithc_reset(ithc); ++ break; ++ case 'w': // write register: offset mask value ++ if (n != 3 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n", ++ a[0], a[2], a[1]); ++ bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]); ++ break; ++ case 'r': // read register: offset ++ if (n != 1 || (a[0] & 3)) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0], ++ readl(((__iomem u32 *)ithc->regs) + a[0] / 4)); ++ break; ++ case 's': // spi command: cmd offset len data... ++ // read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ // set touch cfg: s 6 12 4 XX ++ if (n < 3 || a[2] > (n - 3) * 4) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]); ++ if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3)) ++ for (u32 i = 0; i < (a[2] + 3) / 4; i++) ++ pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]); ++ break; ++ case 'd': // dma command: cmd len data... ++ // get report descriptor: d 7 8 0 0 ++ // enable multitouch: d 3 2 0x0105 ++ if (n < 1) ++ return -EINVAL; ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) ++ pci_err(ithc->pci, "dma tx failed\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ithc_log_regs(ithc); ++ return len; ++} ++ ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ ++static const struct file_operations ithc_debugfops_cmd = { ++ .owner = THIS_MODULE, ++ .write = ithc_debugfs_cmd_write, ++}; ++ ++static void ithc_debugfs_devres_release(struct device *dev, void *res) ++{ ++ struct dentry **dbgm = res; ++ debugfs_remove_recursive(*dbgm); ++} ++ ++int ithc_debug_init_device(struct ithc *ithc) ++{ ++ if (!dbg_dir) ++ return -ENOENT; ++ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); ++ if (!dbgm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, dbgm); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); ++ if (IS_ERR(dbg)) ++ return PTR_ERR(dbg); ++ *dbgm = dbg; ++ ++ struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd); ++ if (IS_ERR(cmd)) ++ return PTR_ERR(cmd); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 000000000000..38c53d916bdb +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +new file mode 100644 +index 000000000000..bf4eab33062b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers. ++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags. ++// This allows each data buffer to consist of multiple non-contiguous blocks of memory. ++ ++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, ++ unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir) ++{ ++ p->num_pages = num_pages; ++ p->dir = dir; ++ // We allocate enough space to have one PRD per data buffer page, however if the data ++ // buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so ++ // some will remain unused (which is fine). ++ p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE); ++ p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL); ++ if (!p->addr) ++ return -ENOMEM; ++ if (p->dma_addr & (PAGE_SIZE - 1)) ++ return -EFAULT; ++ return 0; ++} ++ ++// Devres managed sg_table wrapper. ++struct ithc_sg_table { ++ void *addr; ++ struct sg_table sgt; ++ enum dma_data_direction dir; ++}; ++static void ithc_dma_sgtable_free(struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_sg(sgt, sg, i) { ++ struct page *p = sg_page(sg); ++ if (p) ++ __free_page(p); ++ } ++ sg_free_table(sgt); ++} ++static void ithc_dma_data_devres_release(struct device *dev, void *res) ++{ ++ struct ithc_sg_table *sgt = res; ++ if (sgt->addr) ++ vunmap(sgt->addr); ++ dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0); ++ ithc_dma_sgtable_free(&sgt->sgt); ++} ++ ++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b) ++{ ++ // We don't use dma_alloc_coherent() for data buffers, because they don't have to be ++ // coherent (they are unidirectional) or contiguous (we can use one PRD per page). ++ // We could use dma_alloc_noncontiguous(), however this still always allocates a single ++ // DMA mapped segment, which is more restrictive than what we need. ++ // Instead we use an sg_table of individually allocated pages. ++ struct page *pages[16]; ++ if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages)) ++ return -EINVAL; ++ b->active_idx = -1; ++ struct ithc_sg_table *sgt = devres_alloc( ++ ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) ++ return -ENOMEM; ++ sgt->dir = prds->dir; ++ ++ if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) { ++ struct scatterlist *sg; ++ int i; ++ bool ok = true; ++ for_each_sgtable_sg(&sgt->sgt, sg, i) { ++ // NOTE: don't need __GFP_DMA for PCI DMA ++ struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!p) { ++ ok = false; ++ break; ++ } ++ sg_set_page(sg, p, PAGE_SIZE, 0); ++ } ++ if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) { ++ devres_add(&ithc->pci->dev, sgt); ++ b->sgt = &sgt->sgt; ++ b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL); ++ if (!b->addr) ++ return -ENOMEM; ++ return 0; ++ } ++ ithc_dma_sgtable_free(&sgt->sgt); ++ } ++ devres_free(sgt); ++ return -ENOMEM; ++} ++ ++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Give a buffer to the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ if (b->active_idx >= 0) { ++ pci_err(ithc->pci, "buffer already active\n"); ++ return -EINVAL; ++ } ++ b->active_idx = idx; ++ if (prds->dir == DMA_TO_DEVICE) { ++ // TX buffer: Caller should have already filled the data buffer, so just fill ++ // the PRD and flush. ++ // (TODO: Support multi-page TX buffers. So far no device seems to use or need ++ // these though.) ++ if (b->data_size > PAGE_SIZE) ++ return -EINVAL; ++ prd->addr = sg_dma_address(b->sgt->sgl) >> 10; ++ prd->size = b->data_size | PRD_FLAG_END; ++ flush_kernel_vmap_range(b->addr, b->data_size); ++ } else if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Reset PRDs. ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ prd->addr = sg_dma_address(sg) >> 10; ++ prd->size = sg_dma_len(sg); ++ prd++; ++ } ++ prd[-1].size |= PRD_FLAG_END; ++ } ++ dma_wmb(); // for the prds ++ dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds, ++ struct ithc_dma_data_buffer *b, unsigned int idx) ++{ ++ // Take a buffer from the THC. ++ struct ithc_phys_region_desc *prd = prds->addr; ++ prd += idx * prds->num_pages; ++ // This is purely a sanity check. We don't strictly need the idx parameter for this ++ // function, because it should always be the same as active_idx, unless we have a bug. ++ if (b->active_idx != idx) { ++ pci_err(ithc->pci, "wrong buffer index\n"); ++ return -EINVAL; ++ } ++ b->active_idx = -1; ++ if (prds->dir == DMA_FROM_DEVICE) { ++ // RX buffer: Calculate actual received data size from PRDs. ++ dma_rmb(); // for the prds ++ b->data_size = 0; ++ struct scatterlist *sg; ++ int i; ++ for_each_sgtable_dma_sg(b->sgt, sg, i) { ++ unsigned int size = prd->size; ++ b->data_size += size & PRD_SIZE_MASK; ++ if (size & PRD_FLAG_END) ++ break; ++ if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) { ++ pci_err(ithc->pci, "truncated prd\n"); ++ break; ++ } ++ prd++; ++ } ++ invalidate_kernel_vmap_range(b->addr, b->data_size); ++ } ++ dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir); ++ return 0; ++} ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_init(&rx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); ++ ++ // Init registers. ++ writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2); ++ lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr); ++ writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs); ++ writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds); ++ u8 head = readb(&ithc->regs->dma_rx[channel].head); ++ if (head) { ++ pci_err(ithc->pci, "head is nonzero (%u)\n", head); ++ return -EIO; ++ } ++ ++ // Init buffers. ++ for (unsigned int i = 0; i < NUM_RX_BUF; i++) ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i); ++ ++ writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail); ++ return 0; ++} ++ ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel) ++{ ++ bitsb_set(&ithc->regs->dma_rx[channel].control, ++ DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status, ++ DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED); ++} ++ ++int ithc_dma_tx_init(struct ithc *ithc) ++{ ++ struct ithc_dma_tx *tx = &ithc->dma_tx; ++ mutex_init(&tx->mutex); ++ ++ // Allocate buffers. ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", ++ ithc->max_tx_size, num_pages); ++ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); ++ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); ++ ++ // Init registers. ++ lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr); ++ writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds); ++ ++ // Init buffers. ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ return 0; ++} ++ ++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) ++{ ++ // Process all filled RX buffers from the ringbuffer. ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ unsigned int n = rx->num_received; ++ u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head); ++ while (1) { ++ u8 tail = n % NUM_RX_BUF; ++ u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG); ++ writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail); ++ // ringbuffer is full if tail_wrap == head_wrap ++ // ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG ++ if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG)) ++ return 0; ++ ++ // take the buffer that the device just filled ++ struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF]; ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail); ++ rx->num_received = ++n; ++ ++ // process data ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } ++ ++ // give the buffer back to the device ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); ++ } ++} ++int ithc_dma_rx(struct ithc *ithc, u8 channel) ++{ ++ struct ithc_dma_rx *rx = &ithc->dma_rx[channel]; ++ mutex_lock(&rx->mutex); ++ int ret = ithc_dma_rx_unlocked(ithc, channel); ++ mutex_unlock(&rx->mutex); ++ return ret; ++} ++ ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) ++{ ++ // Send a single TX buffer to the THC. ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); ++ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ ++ // Fill the TX buffer with header and data. ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; ++ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } ++ ++ // Let the THC process the buffer. ++ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); ++ CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); ++ return 0; ++} ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) ++{ ++ mutex_lock(&ithc->dma_tx.mutex); ++ int ret = ithc_dma_tx_unlocked(ithc, data); ++ mutex_unlock(&ithc->dma_tx.mutex); ++ return ret; ++} ++ +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +new file mode 100644 +index 000000000000..1749a5819b3e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define PRD_SIZE_MASK 0xffffff ++#define PRD_FLAG_END 0x1000000 ++#define PRD_FLAG_SUCCESS 0x2000000 ++#define PRD_FLAG_ERROR 0x4000000 ++ ++struct ithc_phys_region_desc { ++ u64 addr; // physical addr/1024 ++ u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds ++ u32 unused; ++}; ++ ++struct ithc_dma_prd_buffer { ++ void *addr; ++ dma_addr_t dma_addr; ++ u32 size; ++ u32 num_pages; // per data buffer ++ enum dma_data_direction dir; ++}; ++ ++struct ithc_dma_data_buffer { ++ void *addr; ++ struct sg_table *sgt; ++ int active_idx; ++ u32 data_size; ++}; ++ ++struct ithc_dma_tx { ++ struct mutex mutex; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer buf; ++}; ++ ++struct ithc_dma_rx { ++ struct mutex mutex; ++ u32 num_received; ++ struct ithc_dma_prd_buffer prds; ++ struct ithc_dma_data_buffer bufs[NUM_RX_BUF]; ++}; ++ ++int ithc_dma_rx_init(struct ithc *ithc, u8 channel); ++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); ++int ithc_dma_tx_init(struct ithc *ithc); ++int ithc_dma_rx(struct ithc *ithc, u8 channel); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); ++ +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 000000000000..065646ab499e +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++static int ithc_hid_start(struct hid_device *hdev) { return 0; } ++static void ithc_hid_stop(struct hid_device *hdev) { } ++static int ithc_hid_open(struct hid_device *hdev) { return 0; } ++static void ithc_hid_close(struct hid_device *hdev) { } ++ ++static int ithc_hid_parse(struct hid_device *hdev) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ WRITE_ONCE(ithc->hid.parse_done, false); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); ++ return 0; ++ } ++ if (retries > 5) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "failed to read report descriptor\n"); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); ++ } ++} ++ ++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, ++ size_t len, unsigned char rtype, int reqtype) ++{ ++ struct ithc *ithc = hdev->driver_data; ++ if (!buf || !len) ++ return -EINVAL; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ ++ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ ++ // Prepare for response. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = buf; ++ ithc->hid.get_feature_size = len; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ ++ // Transmit 'get feature' request. ++ int r = CHECK(ithc_dma_tx, ithc, &d); ++ if (!r) { ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); ++ if (!r) ++ r = -ETIMEDOUT; ++ else if (r < 0) ++ r = -EINTR; ++ else ++ r = 0; ++ } ++ ++ // If everything went ok, the buffer has been filled with the response data. ++ // Return the response size. ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ ithc->hid.get_feature_buf = NULL; ++ if (!r) ++ r = ithc->hid.get_feature_size; ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ return r; ++ } ++ ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } ++} ++ ++static struct hid_ll_driver ithc_ll_driver = { ++ .start = ithc_hid_start, ++ .stop = ithc_hid_stop, ++ .open = ithc_hid_open, ++ .close = ithc_hid_close, ++ .parse = ithc_hid_parse, ++ .raw_request = ithc_hid_raw_request, ++}; ++ ++static void ithc_hid_devres_release(struct device *dev, void *res) ++{ ++ struct hid_device **hidm = res; ++ if (*hidm) ++ hid_destroy_device(*hidm); ++} ++ ++int ithc_hid_init(struct ithc *ithc) ++{ ++ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); ++ if (!hidm) ++ return -ENOMEM; ++ devres_add(&ithc->pci->dev, hidm); ++ struct hid_device *hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ *hidm = hid; ++ ++ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); ++ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); ++ hid->ll_driver = &ithc_ll_driver; ++ hid->bus = BUS_PCI; ++ hid->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; ++ hid->version = 0x100; ++ hid->dev.parent = &ithc->pci->dev; ++ hid->driver_data = ithc; ++ ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; ++ ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; ++ ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; ++ ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); ++ +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) ++ ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) ++ ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" ++ ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? ++ ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); ++ ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 ++ ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 ++ ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); ++} ++ ++int ithc_legacy_init(struct ithc *ithc) ++{ ++ // Since we don't yet know which SPI config the device wants, use default speed and mode ++ // initially for reading config data. ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); ++ ++ // Setting the following bit seems to make reading the config more reliable. ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } ++ ++ // Take the touch device out of reset. ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) ++ break; ++ if (retries > 5) { ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); ++ return -ETIMEDOUT; ++ } ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ if (msleep_interruptible(1000)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ ++ // Read configuration data. ++ u32 spi_cfg; ++ for (int retries = 0; ; retries++) { ++ ithc_log_regs(ithc); ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; ++ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; ++ break; ++ } ++ if (retries > 10) { ++ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ++ config.device_id); ++ return -EIO; ++ } ++ pci_warn(ithc->pci, "failed to read config, retrying\n"); ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ } ++ ithc_log_regs(ithc); ++ ++ // Apply SPI config and enable touch device. ++ CHECK_RET(ithc_set_spi_config, ithc, ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); ++ CHECK_RET(ithc_set_device_enabled, ithc, true); ++ ithc_log_regs(ithc); ++ return 0; ++} ++ ++void ithc_legacy_exit(struct ithc *ithc) ++{ ++ CHECK(ithc_set_device_enabled, ithc, false); ++} ++ ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; ++ ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; ++ ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..094d878d671b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,438 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const struct pci_device_id ithc_pci_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) }, ++ // MTL and up are handled by drivers/hid/intel-thc-hid ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl); ++ ++// Module parameters ++ ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); ++ ++// Since all known devices seem to use only channel 1, by default we disable channel 0. ++static bool ithc_use_rx0 = false; ++module_param_named(rx0, ithc_use_rx0, bool, 0); ++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0"); ++ ++static bool ithc_use_rx1 = true; ++module_param_named(rx1, ithc_use_rx1, bool, 0); ++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); ++ ++static int ithc_active_ltr_us = -1; ++module_param_named(activeltr, ithc_active_ltr_us, int, 0); ++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); ++ ++static int ithc_idle_ltr_us = -1; ++module_param_named(idleltr, ithc_idle_ltr_us, int, 0); ++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); ++ ++static unsigned int ithc_idle_delay_ms = 1000; ++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0); ++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)"); ++ ++static bool ithc_log_regs_enabled = false; ++module_param_named(logregs, ithc_log_regs_enabled, bool, 0); ++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); ++ ++// Interrupts/polling ++ ++static void ithc_disable_interrupts(struct ithc *ithc) ++{ ++ writel(0, &ithc->regs->error_control); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); ++} ++ ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) ++{ ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); ++} ++ ++static void ithc_clear_interrupts(struct ithc *ithc) ++{ ++ writel(0xffffffff, &ithc->regs->error_flags); ++ writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status); ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2, ++ &ithc->regs->dma_tx.status); ++} ++ ++static void ithc_idle_timer_callback(struct timer_list *t) ++{ ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); ++} ++ ++static void ithc_process(struct ithc *ithc) ++{ ++ ithc_log_regs(ithc); ++ ++ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. ++ // It does not appear to automatically go back to idle, so we switch it back after a delay. ++ mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms)); ++ ++ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; ++ ++ // Read and clear error bits ++ u32 err = readl(&ithc->regs->error_flags); ++ if (err) { ++ writel(err, &ithc->regs->error_flags); ++ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "error flags: 0x%08x\n", err); ++ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) ++ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); ++ } ++ ++ // Process DMA rx ++ if (ithc_use_rx0) { ++ ithc_clear_dma_rx_interrupts(ithc, 0); ++ if (rx0) ++ ithc_dma_rx(ithc, 0); ++ } ++ if (ithc_use_rx1) { ++ ithc_clear_dma_rx_interrupts(ithc, 1); ++ if (rx1) ++ ithc_dma_rx(ithc, 1); ++ } ++ ++ ithc_log_regs(ithc); ++} ++ ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++{ ++ struct ithc *ithc = arg; ++ pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n", ++ readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags), ++ readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status), ++ readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status), ++ readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status), ++ readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status)); ++ ithc_process(ithc); ++ return IRQ_HANDLED; ++} ++ ++static int ithc_poll_thread(void *arg) ++{ ++ struct ithc *ithc = arg; ++ unsigned int sleep = 100; ++ while (!kthread_should_stop()) { ++ u32 n = ithc->dma_rx[1].num_received; ++ ithc_process(ithc); ++ // Decrease polling interval to 20ms if we received data, otherwise slowly ++ // increase it up to 200ms. ++ sleep = n != ithc->dma_rx[1].num_received ? 20 ++ : min(200u, sleep + (sleep >> 4) + 1); ++ msleep_interruptible(sleep); ++ } ++ return 0; ++} ++ ++// Device initialization and shutdown ++ ++static void ithc_disable(struct ithc *ithc) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); ++ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0); ++ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0); ++ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0); ++ ithc_disable_interrupts(ithc); ++ ithc_clear_interrupts(ithc); ++} ++ ++static int ithc_init_device(struct ithc *ithc) ++{ ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; ++ ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); ++ ++ // If the device was previously enabled, wait a bit to make sure it's fully shut down. ++ if (was_enabled) ++ if (msleep_interruptible(100)) ++ return -EINTR; ++ ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); ++ ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); ++ ++ return 0; ++} ++ ++int ithc_reset(struct ithc *ithc) ++{ ++ // FIXME This should probably do devres_release_group()+ithc_start(). ++ // But because this is called during DMA processing, that would have to be done ++ // asynchronously (schedule_work()?). And with extra locking? ++ pci_err(ithc->pci, "reset\n"); ++ CHECK(ithc_init_device, ithc); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "reset completed\n"); ++ return 0; ++} ++ ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); ++ ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ timer_delete_sync(&ithc->idle_timer); ++ ++ // Clear DMA config. ++ for (unsigned int i = 0; i < 2; i++) { ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0); ++ lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr); ++ writeb(0, &ithc->regs->dma_rx[i].num_bufs); ++ writeb(0, &ithc->regs->dma_rx[i].num_prds); ++ } ++ lo_hi_writeq(0, &ithc->regs->dma_tx.addr); ++ writeb(0, &ithc->regs->dma_tx.num_prds); ++ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} ++ ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} ++ ++static int ithc_start(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "starting\n"); ++ if (pci_get_drvdata(pci)) { ++ pci_err(pci, "device already initialized\n"); ++ return -EINVAL; ++ } ++ if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ // Allocate/init main driver struct. ++ struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL); ++ if (!ithc) ++ return -ENOMEM; ++ ithc->irq = -1; ++ ithc->pci = pci; ++ snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); ++ pci_set_drvdata(pci, ithc); ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); ++ if (ithc_log_regs_enabled) ++ ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL); ++ ++ // PCI initialization. ++ CHECK_RET(pcim_enable_device, pci); ++ pci_set_master(pci); ++ CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs"); ++ CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64)); ++ CHECK_RET(pci_set_power_state, pci, PCI_D0); ++ ithc->regs = pcim_iomap_table(pci)[0]; ++ ++ // Allocate IRQ. ++ if (!ithc_use_polling) { ++ CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX); ++ ithc->irq = CHECK(pci_irq_vector, pci, 0); ++ if (ithc->irq < 0) ++ return ithc->irq; ++ } ++ ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); ++ ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); ++ ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); ++ ++ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are ++ // disabled BEFORE the buffers are freed. ++ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); ++ ++ // Start polling/IRQ. ++ if (ithc_use_polling) { ++ pci_info(pci, "using polling instead of irq\n"); ++ // Use a thread instead of simple timer because we want to be able to sleep. ++ ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll"); ++ if (IS_ERR(ithc->poll_thread)) { ++ int err = PTR_ERR(ithc->poll_thread); ++ ithc->poll_thread = NULL; ++ return err; ++ } ++ } else { ++ CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ++ ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc); ++ } ++ ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); ++ ++ // hid_add_device() can only be called after irq/polling is started and DMA is enabled, ++ // because it calls ithc_hid_parse() which reads the report descriptor via DMA. ++ CHECK_RET(hid_add_device, ithc->hid.dev); ++ ++ CHECK(ithc_debug_init_device, ithc); ++ ++ ithc_set_ltr_idle(ithc); ++ ++ pci_dbg(pci, "started\n"); ++ return 0; ++} ++ ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} ++ ++static void ithc_remove(struct pci_dev *pci) ++{ ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres ++} ++ ++// For suspend/resume, we just deinitialize and reinitialize everything. ++// TODO It might be cleaner to keep the HID device around, however we would then have to signal ++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set ++// feature' requests. Hidraw does not seem to have a facility to do that. ++static int ithc_suspend(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_resume(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm resume\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_freeze(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm freeze\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; ++} ++ ++static int ithc_thaw(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); ++} ++ ++static int ithc_restore(struct device *dev) ++{ ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm restore\n"); ++ return ithc_start(pci); ++} ++ ++static struct pci_driver ithc_driver = { ++ .name = DEVNAME, ++ .id_table = ithc_pci_tbl, ++ .probe = ithc_probe, ++ .remove = ithc_remove, ++ .driver.pm = &(const struct dev_pm_ops) { ++ .suspend = ithc_suspend, ++ .resume = ithc_resume, ++ .freeze = ithc_freeze, ++ .thaw = ithc_thaw, ++ .restore = ithc_restore, ++ }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, ++}; ++ ++static int __init ithc_init(void) ++{ ++ ithc_debug_init_module(); ++ return pci_register_driver(&ithc_driver); ++} ++ ++static void __exit ithc_exit(void) ++{ ++ pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); ++} ++ ++module_init(ithc_init); ++module_exit(ithc_exit); ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 000000000000..e2d1690b8cf8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,607 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static void set_opcode(struct ithc *ithc, size_t i, u8 opcode) ++{ ++ writeb(opcode, &ithc->regs->opcode[i].header); ++ writeb(opcode, &ithc->regs->opcode[i].single); ++ writeb(opcode, &ithc->regs->opcode[i].dual); ++ writeb(opcode, &ithc->regs->opcode[i].quad); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) { ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr); ++ } ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ switch (ithc->pci->device) { ++ // LKF/TGL don't support QuickSPI. ++ // For ADL, opcode layout is RX/TX/unused. ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 1, cfg->write_opcode); ++ } ++ break; ++ // For MTL, opcode layout was changed to RX/RX/TX. ++ // (RPL layout is unknown.) ++ default: ++ if (cfg->has_read_opcode) { ++ set_opcode(ithc, 0, cfg->read_opcode); ++ set_opcode(ithc, 1, cfg->read_opcode); ++ } ++ if (cfg->has_write_opcode) { ++ set_opcode(ithc, 2, cfg->write_opcode); ++ } ++ break; ++ } ++ ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 000000000000..74d882f6b2f0 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +new file mode 100644 +index 000000000000..c0f13506af20 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++#include "ithc.h" ++ ++#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writel((readl(reg) & ~mask) | (val & mask), reg); ++} ++ ++void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++{ ++ if (val & ~mask) ++ pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n", ++ reg_num(reg), val, mask); ++ writeb((readb(reg) & ~mask) | (val & mask), reg); ++} ++ ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ u32 x; ++ if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) ++{ ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ u8 x; ++ if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); ++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", ++ reg_num(reg), mask, val); ++ return -ETIMEDOUT; ++ } ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "done waiting\n"); ++ return 0; ++} ++ ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) ++{ ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); ++ return 0; ++} ++ ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++{ ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); ++ if (size > sizeof(ithc->regs->spi_cmd.data)) ++ return -EINVAL; ++ ++ // Wait if the device is still busy. ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ // Clear result flags. ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ ++ // Init SPI command data. ++ writeb(command, &ithc->regs->spi_cmd.code); ++ writew(size, &ithc->regs->spi_cmd.size); ++ writel(offset, &ithc->regs->spi_cmd.offset); ++ u32 *p = data, n = (size + 3) / 4; ++ for (u32 i = 0; i < n; i++) ++ writel(p[i], &ithc->regs->spi_cmd.data[i]); ++ ++ // Start transmission. ++ bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND); ++ CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0); ++ ++ // Read response. ++ if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE) ++ return -EIO; ++ if (readw(&ithc->regs->spi_cmd.size) != size) ++ return -EMSGSIZE; ++ for (u32 i = 0; i < n; i++) ++ p[i] = readl(&ithc->regs->spi_cmd.data[i]); ++ ++ writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status); ++ return 0; ++} ++ +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +new file mode 100644 +index 000000000000..4f541fe533fa +--- /dev/null ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ ++#define CONTROL_QUIESCE BIT(1) ++#define CONTROL_IS_QUIESCED BIT(2) ++#define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) ++#define CONTROL_READY BIT(29) ++ ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 ++ ++#define ERROR_CONTROL_UNKNOWN_0 BIT(0) ++#define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs ++#define ERROR_CONTROL_UNKNOWN_2 BIT(2) ++#define ERROR_CONTROL_UNKNOWN_3 BIT(3) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12 BIT(12) ++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_CONTROL_UNKNOWN_16(x) (((x) & 0xff) << 16) // spi error code irq? ++#define ERROR_CONTROL_SET_DMA_STATUS BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs ++ ++#define ERROR_STATUS_DMA BIT(28) ++#define ERROR_STATUS_SPI BIT(30) ++ ++#define ERROR_FLAG_DMA_UNKNOWN_9 BIT(9) ++#define ERROR_FLAG_DMA_UNKNOWN_10 BIT(10) ++#define ERROR_FLAG_DMA_RX_TIMEOUT BIT(12) // set when we receive a truncated DMA message ++#define ERROR_FLAG_DMA_UNKNOWN_13 BIT(13) ++#define ERROR_FLAG_SPI_BUS_TURNAROUND BIT(16) ++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT BIT(17) ++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18) ++#define ERROR_FLAG_SPI_INVALID_RESPONSE BIT(19) ++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT BIT(20) ++#define ERROR_FLAG_SPI_TOUCH_IC_INIT BIT(21) ++ ++#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define SPI_CMD_CONTROL_IRQ BIT(1) ++ ++#define SPI_CMD_CODE_READ 4 ++#define SPI_CMD_CODE_WRITE 6 ++ ++#define SPI_CMD_STATUS_DONE BIT(0) ++#define SPI_CMD_STATUS_ERROR BIT(1) ++#define SPI_CMD_STATUS_BUSY BIT(3) ++ ++#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete ++#define DMA_TX_CONTROL_IRQ BIT(3) ++ ++#define DMA_TX_STATUS_DONE BIT(0) ++#define DMA_TX_STATUS_ERROR BIT(1) ++#define DMA_TX_STATUS_UNKNOWN_2 BIT(2) ++#define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? ++ ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ ++#define DMA_RX_CONTROL_ENABLE BIT(0) ++#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only ++#define DMA_RX_CONTROL_IRQ_DATA BIT(5) ++ ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? ++#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? ++#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ ++#define DMA_RX_WRAP_FLAG BIT(7) ++ ++#define DMA_RX_STATUS_ERROR BIT(3) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_HAVE_DATA BIT(5) ++#define DMA_RX_STATUS_ENABLED BIT(8) ++ ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ ++// COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. ++#define COUNTER_RESET BIT(31) ++ ++struct ithc_registers { ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; ++ /* 1000 */ u32 _unknown_1000; ++ /* 1004 */ u32 _unknown_1004; ++ /* 1008 */ u32 control_bits; ++ /* 100c */ u32 _unknown_100c; ++ /* 1010 */ u32 spi_config; ++ struct { ++ /* 1014/1018/101c */ u8 header; ++ /* 1015/1019/101d */ u8 quad; ++ /* 1016/101a/101e */ u8 dual; ++ /* 1017/101b/101f */ u8 single; ++ } opcode[3]; ++ /* 1020 */ u32 error_control; ++ /* 1024 */ u32 error_status; // write to clear ++ /* 1028 */ u32 error_flags; // write to clear ++ /* 102c */ u32 _unknown_102c[5]; ++ struct { ++ /* 1040 */ u8 control; ++ /* 1041 */ u8 code; ++ /* 1042 */ u16 size; ++ /* 1044 */ u32 status; // write to clear ++ /* 1048 */ u32 offset; ++ /* 104c */ u32 data[16]; ++ /* 108c */ u32 _unknown_108c; ++ } spi_cmd; ++ struct { ++ /* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1098 */ u8 control; ++ /* 1099 */ u8 _unknown_1099; ++ /* 109a */ u8 _unknown_109a; ++ /* 109b */ u8 num_prds; ++ /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; ++ } dma_tx; ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; ++ /* 10c0 */ u32 _unknown_10c0[8]; ++ /* 10e0 */ u32 _unknown_10e0_counters[3]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; ++ struct { ++ /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() ++ /* 1108/1208 */ u8 num_bufs; ++ /* 1109/1209 */ u8 num_prds; ++ /* 110a/120a */ u16 _unknown_110a; ++ /* 110c/120c */ u8 control; ++ /* 110d/120d */ u8 head; ++ /* 110e/120e */ u8 tail; ++ /* 110f/120f */ u8 control2; ++ /* 1110/1210 */ u32 status; // write to clear ++ /* 1114/1214 */ u32 _unknown_1114; ++ /* 1118/1218 */ u64 _unknown_1118_guc_addr; ++ /* 1120/1220 */ u32 _unknown_1120_guc; ++ /* 1124/1224 */ u32 _unknown_1124_guc; ++ /* 1128/1228 */ u32 init_unknown; ++ /* 112c/122c */ u32 _unknown_112c; ++ /* 1130/1230 */ u64 _unknown_1130_guc_addr; ++ /* 1138/1238 */ u32 _unknown_1138_guc; ++ /* 113c/123c */ u32 _unknown_113c; ++ /* 1140/1240 */ u32 _unknown_1140_guc; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; ++ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; ++ /* 11b8/12b8 */ u32 _unknown_11b8[18]; ++ } dma_rx[2]; ++}; ++static_assert(sizeof(struct ithc_registers) == 0x1300); ++ ++void bitsl(__iomem u32 *reg, u32 mask, u32 val); ++void bitsb(__iomem u8 *reg, u8 mask, u8 val); ++#define bitsl_set(reg, x) bitsl(reg, x, x) ++#define bitsb_set(reg, x) bitsb(reg, x, x) ++int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); ++int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); ++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); ++ +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +new file mode 100644 +index 000000000000..aec320d4e945 +--- /dev/null ++++ b/drivers/hid/ithc/ithc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVNAME "ithc" ++#define DEVFULLNAME "Intel Touch Host Controller" ++ ++#undef pr_fmt ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; }) ++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0) ++ ++#define NUM_RX_BUF 16 ++ ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT1 0x7f59 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2 0x7f5b ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b ++ ++struct ithc; ++ ++#include "ithc-regs.h" ++#include "ithc-hid.h" ++#include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" ++ ++struct ithc { ++ char phys[32]; ++ struct pci_dev *pci; ++ int irq; ++ struct task_struct *poll_thread; ++ struct timer_list idle_timer; ++ ++ struct ithc_registers __iomem *regs; ++ struct ithc_registers *prev_regs; // for debugging ++ struct ithc_dma_rx dma_rx[2]; ++ struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; ++}; ++ ++int ithc_reset(struct ithc *ithc); ++ +-- +2.53.0 + diff --git a/patches/6.19/0007-surface-sam.patch b/patches/6.19/0007-surface-sam.patch new file mode 100644 index 0000000000..ee42aaea25 --- /dev/null +++ b/patches/6.19/0007-surface-sam.patch @@ -0,0 +1,211 @@ +From ce0fa0a3ecff792f7a9bfdac05d8fa21718a0dff Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Fri, 17 Jun 2022 02:14:00 +0200 +Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator + Module + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/rtc/Kconfig | 7 +++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-surface.c | 129 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 137 insertions(+) + create mode 100644 drivers/rtc/rtc-surface.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 50dc779f7f98..63aaff40a0fd 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1423,6 +1423,13 @@ config RTC_DRV_NTXEC + embedded controller found in certain e-book readers designed by the + original design manufacturer Netronix. + ++config RTC_DRV_SURFACE ++ tristate "Microsoft Surface Aggregator RTC" ++ depends on SURFACE_AGGREGATOR ++ depends on SURFACE_AGGREGATOR_BUS ++ help ++ TODO ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_ASM9260 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 6cf7e066314e..18bd33b84d13 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -186,6 +186,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o + obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o + obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o + obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o ++obj-$(CONFIG_RTC_DRV_SURFACE) += rtc-surface.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o +diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c +new file mode 100644 +index 000000000000..f6c17c4e98d5 +--- /dev/null ++++ b/drivers/rtc/rtc-surface.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * AC driver for 7th-generation Microsoft Surface devices via Surface System ++ * Aggregator Module (SSAM). ++ * ++ * Copyright (C) 2019-2021 Maximilian Luz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct surface_rtc { ++ struct ssam_device *sdev; ++ struct rtc_device *rtc; ++}; ++ ++SSAM_DEFINE_SYNC_REQUEST_R(__ssam_rtc_get_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x10, ++}); ++ ++SSAM_DEFINE_SYNC_REQUEST_W(__ssam_rtc_set_unix_time, __le32, { ++ .target_category = SSAM_SSH_TC_SAM, ++ .target_id = SSAM_SSH_TID_SAM, ++ .instance_id = 0x00, ++ .command_id = 0x0f, ++}); ++ ++static int ssam_rtc_get_unix_time(struct surface_rtc *srtc, u32 *time) ++{ ++ __le32 time_le; ++ int status; ++ ++ status = __ssam_rtc_get_unix_time(srtc->sdev->ctrl, &time_le); ++ if (status) ++ return status; ++ ++ *time = le32_to_cpu(time_le); ++ return 0; ++} ++ ++static int ssam_rtc_set_unix_time(struct surface_rtc *srtc, u32 time) ++{ ++ __le32 time_le = cpu_to_le32(time); ++ ++ return __ssam_rtc_set_unix_time(srtc->sdev->ctrl, &time_le); ++} ++ ++static int surface_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ int status; ++ u32 time; ++ ++ status = ssam_rtc_get_unix_time(srtc, &time); ++ if (status) ++ return status; ++ ++ rtc_time64_to_tm(time, tm); ++ return 0; ++} ++ ++static int surface_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct surface_rtc *srtc = dev_get_drvdata(dev); ++ time64_t time = rtc_tm_to_time64(tm); ++ ++ return ssam_rtc_set_unix_time(srtc, (u32)time); ++} ++ ++static const struct rtc_class_ops surface_rtc_ops = { ++ .read_time = surface_rtc_read_time, ++ .set_time = surface_rtc_set_time, ++}; ++ ++static int surface_rtc_probe(struct ssam_device *sdev) ++{ ++ struct surface_rtc *srtc; ++ ++ srtc = devm_kzalloc(&sdev->dev, sizeof(*srtc), GFP_KERNEL); ++ if (!srtc) ++ return -ENOMEM; ++ ++ srtc->sdev = sdev; ++ ++ srtc->rtc = devm_rtc_allocate_device(&sdev->dev); ++ if (IS_ERR(srtc->rtc)) ++ return PTR_ERR(srtc->rtc); ++ ++ srtc->rtc->ops = &surface_rtc_ops; ++ srtc->rtc->range_max = U32_MAX; ++ ++ ssam_device_set_drvdata(sdev, srtc); ++ ++ return devm_rtc_register_device(srtc->rtc); ++} ++ ++static void surface_rtc_remove(struct ssam_device *sdev) ++{ ++ /* Device-managed allocations take care of everything... */ ++} ++ ++static const struct ssam_device_id surface_rtc_match[] = { ++ { SSAM_SDEV(SAM, SAM, 0x00, 0x00) }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(ssam, surface_rtc_match); ++ ++static struct ssam_device_driver surface_rtc_driver = { ++ .probe = surface_rtc_probe, ++ .remove = surface_rtc_remove, ++ .match_table = surface_rtc_match, ++ .driver = { ++ .name = "surface_rtc", ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ }, ++}; ++module_ssam_device_driver(surface_rtc_driver); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("RTC driver for Surface System Aggregator Module"); ++MODULE_LICENSE("GPL"); +-- +2.53.0 + +From 88065461b3da56157ade06b0cbab4b4bf2aa5cac Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 20 Apr 2025 01:05:14 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 + (ACPI) + +Patchset: surface-sam +--- + drivers/platform/surface/surface_aggregator_registry.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c +index 78ac3a8fbb73..10fe004e4e21 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { + /* Surface Laptop 6 */ + { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, + ++ /* Surface Laptop 7 */ ++ { "MSHW0551", (unsigned long)ssam_node_group_sl7 }, ++ + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + +-- +2.53.0 + diff --git a/patches/6.19/0008-surface-sam-over-hid.patch b/patches/6.19/0008-surface-sam-over-hid.patch new file mode 100644 index 0000000000..969dfce8b5 --- /dev/null +++ b/patches/6.19/0008-surface-sam-over-hid.patch @@ -0,0 +1,308 @@ +From 2e4050a5807541e471392dccf9548e88489e70b6 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 25 Jul 2020 17:19:53 +0200 +Subject: [PATCH] i2c: acpi: Implement RawBytes read access + +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Signed-off-by: Maximilian Luz +Patchset: surface-sam-over-hid +--- + drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index ed90858a27b7..070c36637811 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + return (ret == 1) ? 0 : -EIO; + } + ++static int acpi_gsb_i2c_write_raw_bytes(struct i2c_client *client, ++ u8 *data, u8 data_len) ++{ ++ struct i2c_msg msgs[1]; ++ int ret; ++ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = client->flags; ++ msgs[0].len = data_len + 1; ++ msgs[0].buf = data; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) { ++ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); ++ return ret; ++ } ++ ++ /* 1 transfer must have completed successfully */ ++ return (ret == 1) ? 0 : -EIO; ++} ++ + static acpi_status + i2c_acpi_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, +@@ -763,6 +784,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, + } + break; + ++ case ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES: ++ if (action == ACPI_READ) { ++ dev_warn(&adapter->dev, ++ "protocol 0x%02x not supported for client 0x%02x\n", ++ accessor_type, client->addr); ++ ret = AE_BAD_PARAMETER; ++ goto err; ++ } else { ++ status = acpi_gsb_i2c_write_raw_bytes(client, ++ gsb->data, info->access_length); ++ } ++ break; ++ + default: + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); +-- +2.53.0 + +From 179eceb312b4dd735e9665d42637fe1805592412 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 13 Feb 2021 16:41:18 +0100 +Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c + +diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index f775c6ca1ec1..2075e3852053 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS ++ help ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. ++ + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 53344330939b..7efcd0cdb532 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c +new file mode 100644 +index 000000000000..68db237734a1 +--- /dev/null ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */ ++static const guid_t dgpu_sw_guid = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); ++ ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" ++ ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *obj; ++ acpi_handle handle; ++ acpi_status status; ++ ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; ++ ++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!obj) ++ return -EINVAL; ++ ++ ACPI_FREE(obj); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGON: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-on dGPU via HGON\n"); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgof(struct device *dev) ++{ ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; ++ ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ dev_err(dev, "failed to run HGOF: %d\n", status); ++ return -EINVAL; ++ } ++ ++ ACPI_FREE(buf.pointer); ++ ++ dev_info(dev, "turned-off dGPU via HGOF\n"); ++ return 0; ++} ++ ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool value; ++ int status; ++ ++ status = kstrtobool(buf, &value); ++ if (status < 0) ++ return status; ++ ++ if (!value) ++ return 0; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++ ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ bool power; ++ int status; ++ ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; ++ ++ if (power) ++ status = sb1_dgpu_sw_hgon(dev); ++ else ++ status = sb1_dgpu_sw_hgof(dev); ++ ++ return status < 0 ? status : len; ++} ++static DEVICE_ATTR_WO(dgpu_power); ++ ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(sb1_dgpu_sw); ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .driver = { ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .dev_groups = sb1_dgpu_sw_groups, ++ }, ++}; ++module_platform_driver(sb1_dgpu_sw); ++ ++MODULE_AUTHOR("Maximilian Luz "); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/patches/6.19/0009-surface-button.patch b/patches/6.19/0009-surface-button.patch new file mode 100644 index 0000000000..c11714a232 --- /dev/null +++ b/patches/6.19/0009-surface-button.patch @@ -0,0 +1,149 @@ +From 93e2e5694855fa7a53c6e465cedf07e18653bd43 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:05:09 +1100 +Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices + +The power button on the AMD variant of the Surface Laptop uses the +same MSHW0040 device ID as the 5th and later generation of Surface +devices, however they report 0 for their OEM platform revision. As the +_DSM does not exist on the devices requiring special casing, check for +the existance of the _DSM to determine if soc_button_array should be +loaded. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- + 1 file changed, 8 insertions(+), 25 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index b8cad415c62c..43b5d56383e3 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned + * devices use MSHW0040 for power and volume buttons, however the way they + * have to be addressed differs. Make sure that we only load this drivers +- * for the correct devices by checking the OEM Platform Revision provided by +- * the _DSM method. ++ * for the correct devices by checking if the OEM Platform Revision DSM call ++ * exists. + */ + #define MSHW0040_DSM_REVISION 0x01 + #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision +@@ -552,31 +552,14 @@ static const guid_t MSHW0040_DSM_UUID = + static int soc_device_check_MSHW0040(struct device *dev) + { + acpi_handle handle = ACPI_HANDLE(dev); +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, NULL, +- ACPI_TYPE_INTEGER); +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- /* +- * If the revision is zero here, the _DSM evaluation has failed. This +- * indicates that we have a Pro 4 or Book 1 and this driver should not +- * be used. +- */ +- if (oem_platform_rev == 0) +- return -ENODEV; ++ bool exists; + +- dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ // check if OEM platform revision DSM call exists ++ exists = acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + +- return 0; ++ return exists ? 0 : -ENODEV; + } + + /* +-- +2.53.0 + +From 63462c31da1c67a2a472be398ddc9ceee69ac32c Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Tue, 5 Oct 2021 00:22:57 +1100 +Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd + variant + +The AMD variant of the Surface Laptop report 0 for their OEM platform +revision. The Surface devices that require the surfacepro3_button +driver do not have the _DSM that gets the OEM platform revision. If the +method does not exist, load surfacepro3_button. + +Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") +Co-developed-by: Maximilian Luz + +Signed-off-by: Sachi King +Patchset: surface-button +--- + drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979c..4240c98ca226 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); + } + + +-- +2.53.0 + diff --git a/patches/6.19/0010-surface-typecover.patch b/patches/6.19/0010-surface-typecover.patch new file mode 100644 index 0000000000..8f457931dc --- /dev/null +++ b/patches/6.19/0010-surface-typecover.patch @@ -0,0 +1,576 @@ +From 65a6164c1eadb5f8ec8ccfa46e6c632ee0de16be Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 18 Feb 2023 01:02:49 +0100 +Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 + Type-Cover + +The touchpad on the Type-Cover of the Surface Go 3 is sometimes not +being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this +issue. + +More specifically, the device in question is a fairly standard modern +touchpad with pointer and touchpad input modes. During setup, the device +needs to be switched from pointer- to touchpad-mode (which is done in +hid-multitouch) to fully utilize it as intended. Unfortunately, however, +this seems to occasionally fail silently, leaving the device in +pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. + +Link: https://github.com/linux-surface/linux-surface/issues/1059 +Signed-off-by: Maximilian Luz +Patchset: surface-typecover +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index c4d85089d19b..3d0d35c72189 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ + { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, + +-- +2.53.0 + +From 5950b1c8141212f47505f566e315858c79f33597 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= +Date: Thu, 5 Nov 2020 13:09:45 +0100 +Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when + suspending + +The Type Cover for Microsoft Surface devices supports a special usb +control request to disable or enable the built-in keyboard backlight. +On Windows, this request happens when putting the device into suspend or +resuming it, without it the backlight of the Type Cover will remain +enabled for some time even though the computer is suspended, which looks +weird to the user. + +So add support for this special usb control request to hid-multitouch, +which is the driver that's handling the Type Cover. + +The reason we have to use a pm_notifier for this instead of the usual +suspend/resume methods is that those won't get called in case the usb +device is already autosuspended. + +Also, if the device is autosuspended, we have to briefly autoresume it +in order to send the request. Doing that should be fine, the usb-core +driver does something similar during suspend inside choose_wakeup(). + +To make sure we don't send that request to every device but only to +devices which support it, add a new quirk +MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk +is only enabled for the usb id of the Surface Pro 2017 Type Cover, which +is where I confirmed that it's working. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- + 1 file changed, 98 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index b1c3ef129058..44ac1d672ee9 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -35,7 +35,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -48,6 +51,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); + MODULE_LICENSE("GPL"); + + #include "hid-ids.h" ++#include "usbhid/usbhid.h" + + #include "hid-haptic.h" + +@@ -76,6 +80,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_DISABLE_WAKEUP BIT(21) + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -83,6 +88,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_CLICKPAD 0 + #define MT_BUTTONTYPE_PRESSUREPAD 1 + ++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++ + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -186,6 +193,8 @@ struct mt_device { + + struct list_head applications; + struct list_head reports; ++ ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -231,6 +240,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 + #define MT_CLS_SMART_TECH 0x0113 + #define MT_CLS_APPLE_TOUCHBAR 0x0114 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -428,6 +438,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + }, ++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_IGNORE_DUPLICATES | ++ MT_QUIRK_HOVERING | ++ MT_QUIRK_CONTACT_CNT_ACCURATE | ++ MT_QUIRK_STICKY_FINGERS | ++ MT_QUIRK_WIN8_PTP_BUTTONS, ++ .export_all_inputs = true ++ }, + { } + }; + +@@ -1853,6 +1873,69 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++static void get_type_cover_backlight_field(struct hid_device *hdev, ++ struct hid_field **field) ++{ ++ struct hid_report_enum *rep_enum; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid ++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { ++ *field = cur_field; ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) ++{ ++ struct usb_device *udev = hid_to_usb_dev(hdev); ++ struct hid_field *field = NULL; ++ ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); ++ ++ get_type_cover_backlight_field(hdev, &field); ++ if (!field) { ++ hid_err(hdev, "couldn't find backlight field\n"); ++ goto out; ++ } ++ ++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff; ++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT); ++ ++out: ++ pm_runtime_put_sync(&udev->dev); ++} ++ ++static int mt_pm_notifier(struct notifier_block *notifier, ++ unsigned long pm_event, ++ void *unused) ++{ ++ struct mt_device *td = ++ container_of(notifier, struct mt_device, pm_notifier); ++ struct hid_device *hdev = td->hdev; ++ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) { ++ if (pm_event == PM_SUSPEND_PREPARE) ++ update_keyboard_backlight(hdev, 0); ++ else if (pm_event == PM_POST_SUSPEND) ++ update_keyboard_backlight(hdev, 1); ++ } ++ ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1881,6 +1964,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + hid_set_drvdata(hdev, td); + ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); + +@@ -1919,8 +2005,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); + + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && + !hid_find_field(hdev, HID_INPUT_REPORT, +@@ -1934,8 +2022,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } + + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1996,6 +2086,7 @@ static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); + ++ unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); + + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2440,6 +2531,11 @@ static const struct hid_device_id mt_devices[] = { + HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, + ++ /* Microsoft Surface type cover */ ++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x09c0) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.53.0 + +From 07990c05b76076db813df4fefa9451595fb123c5 Mon Sep 17 00:00:00 2001 +From: PJungkamp +Date: Fri, 25 Feb 2022 12:04:25 +0100 +Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet + switch + +The Surface Pro Type Cover has several non standard HID usages in it's +hid report descriptor. +I noticed that, upon folding the typecover back, a vendor specific range +of 4 32 bit integer hid usages is transmitted. +Only the first byte of the message seems to convey reliable information +about the keyboard state. + +0x22 => Normal (keys enabled) +0x33 => Folded back (keys disabled) +0x53 => Rotated left/right side up (keys disabled) +0x13 => Cover closed (keys disabled) +0x43 => Folded back and Tablet upside down (keys disabled) +This list may not be exhaustive. + +The tablet mode switch will be disabled for a value of 0x22 and enabled +on any other value. + +Patchset: surface-typecover +--- + drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ + 1 file changed, 122 insertions(+), 26 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 44ac1d672ee9..bd2554f2127f 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -81,6 +81,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_ORIENTATION_INVERT BIT(22) + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -89,6 +90,8 @@ MODULE_LICENSE("GPL"); + #define MT_BUTTONTYPE_PRESSUREPAD 1 + + #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 ++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072 ++#define MS_TYPE_COVER_APPLICATION 0xff050050 + + enum latency_mode { + HID_LATENCY_NORMAL = 0, +@@ -440,6 +443,7 @@ static const struct mt_class mt_classes[] = { + }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | ++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH | + MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | +@@ -1474,6 +1478,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + field->application != HID_CP_CONSUMER_CONTROL && + field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && ++ !(field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) && + !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + return -1; +@@ -1501,6 +1508,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++ /* ++ * The Microsoft Surface Pro Typecover has a non-standard HID ++ * tablet mode switch on a vendor specific usage page with vendor ++ * specific usage. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ usage->type = EV_SW; ++ usage->code = SW_TABLET_MODE; ++ *max = SW_MAX; ++ *bit = hi->input->swbit; ++ return 1; ++ } ++ + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); +@@ -1527,6 +1549,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + { + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { +@@ -1534,6 +1557,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + return -1; + } + ++ /* ++ * We own an input device which acts as a tablet mode switch for ++ * the Surface Pro Typecover. ++ */ ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = hi->input; ++ input_set_capability(input, EV_SW, SW_TABLET_MODE); ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ return -1; ++ } ++ + /* let hid-core decide for the others */ + return 0; + } +@@ -1543,11 +1579,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, + { + struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; ++ struct input_dev *input; + + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) + return mt_touch_event(hid, field, usage, value); + ++ if (field->application == MS_TYPE_COVER_APPLICATION && ++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH && ++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22); ++ input_sync(input); ++ return 1; ++ } ++ + return 0; + } + +@@ -1730,6 +1776,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } + ++static int get_type_cover_field(struct hid_report_enum *rep_enum, ++ struct hid_field **field, int usage) ++{ ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; ++ ++ list_for_each_entry(rep, &rep_enum->report_list, list) { ++ for (i = 0; i < rep->maxfield; i++) { ++ cur_field = rep->field[i]; ++ if (cur_field->application != MS_TYPE_COVER_APPLICATION) ++ continue; ++ for (j = 0; j < cur_field->maxusage; j++) { ++ if (cur_field->usage[j].hid == usage) { ++ *field = cur_field; ++ return true; ++ } ++ } ++ } ++ } ++ return false; ++} ++ ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; ++ ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++} ++ + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1787,6 +1869,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; ++ case MS_TYPE_COVER_APPLICATION: ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ suffix = "Tablet Mode Switch"; ++ request_type_cover_tablet_mode_switch(hdev); ++ break; ++ } ++ fallthrough; + default: + suffix = "UNKNOWN"; + break; +@@ -1873,30 +1962,6 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + +-static void get_type_cover_backlight_field(struct hid_device *hdev, +- struct hid_field **field) +-{ +- struct hid_report_enum *rep_enum; +- struct hid_report *rep; +- struct hid_field *cur_field; +- int i, j; +- +- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; +- list_for_each_entry(rep, &rep_enum->report_list, list) { +- for (i = 0; i < rep->maxfield; i++) { +- cur_field = rep->field[i]; +- +- for (j = 0; j < cur_field->maxusage; j++) { +- if (cur_field->usage[j].hid +- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) { +- *field = cur_field; +- return; +- } +- } +- } +- } +-} +- + static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + { + struct usb_device *udev = hid_to_usb_dev(hdev); +@@ -1905,8 +1970,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) + /* Wake up the device in case it's already suspended */ + pm_runtime_get_sync(&udev->dev); + +- get_type_cover_backlight_field(hdev, &field); +- if (!field) { ++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT], ++ &field, ++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) { + hid_err(hdev, "couldn't find backlight field\n"); + goto out; + } +@@ -2064,13 +2130,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) + + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); ++ ++ /* Request an update on the typecover folding state on resume ++ * after reset. ++ */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* Some Elan legacy devices require SET_IDLE to be set on resume. + * It should be safe to send it to other devices too. + * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ +@@ -2079,12 +2156,31 @@ static int mt_resume(struct hid_device *hdev) + + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + ++ /* Request an update on the typecover folding state on resume. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) ++ request_type_cover_tablet_mode_switch(hdev); ++ + return 0; + } + + static void mt_remove(struct hid_device *hdev) + { + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; ++ ++ /* Reset tablet mode switch on disconnect. */ ++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) { ++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT], ++ &field, ++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) { ++ input = field->hidinput->input; ++ input_report_switch(input, SW_TABLET_MODE, 0); ++ input_sync(input); ++ } else { ++ hid_err(hdev, "couldn't find tablet mode field\n"); ++ } ++ } + + unregister_pm_notifier(&td->pm_notifier); + timer_delete_sync(&td->release_timer); +-- +2.53.0 + diff --git a/patches/6.19/0011-surface-shutdown.patch b/patches/6.19/0011-surface-shutdown.patch new file mode 100644 index 0000000000..b414542211 --- /dev/null +++ b/patches/6.19/0011-surface-shutdown.patch @@ -0,0 +1,140 @@ +From f1da140af03cace2df8b9462fe4ce041bf8dd954 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 19 Feb 2023 22:12:24 +0100 +Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method + +Work around buggy EFI firmware: On some Microsoft Surface devices +(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with +EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the +system down, it returns and the system stays on. + +It turns out that this only happens after PCI shutdown callbacks ran for +specific devices. Excluding those devices from the shutdown process +makes the ResetSystem call work as expected. + +TODO: Maybe we can find a better way or the root cause of this? + +Not-Signed-off-by: Maximilian Luz +Patchset: surface-shutdown +--- + drivers/pci/pci-driver.c | 3 +++ + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/pci.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 7c2d9d596258..dc792984c2a7 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 280cd50d693b..454d1cb23dde 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6340,3 +6340,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU +diff --git a/include/linux/pci.h b/include/linux/pci.h +index b5cc0c2b9906..9cd35904dafc 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -488,6 +488,7 @@ struct pci_dev { + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ + unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ + unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +-- +2.53.0 + +From 1fbb5e7dcfcfafc56d810d0c3bb974211fd35c7b Mon Sep 17 00:00:00 2001 +From: LegendaryFire +Date: Wed, 7 Jan 2026 01:06:25 +0100 +Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops + quirk + +Link: https://github.com/linux-surface/linux-surface/pull/1948 +Patchset: surface-shutdown +--- + drivers/pci/quirks.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 454d1cb23dde..7d2e7f6572db 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6359,6 +6359,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop Studio 2", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop Studio 2"), ++ }, ++ }, + {} + }; + +@@ -6376,3 +6383,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thu + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU ++ ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa76e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa71e, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa73f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa73e, quirk_no_shutdown); // Thunderbolt 4 NHI ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0xa7a0, quirk_no_shutdown); // GPU +-- +2.53.0 + diff --git a/patches/6.19/0012-surface-gpe.patch b/patches/6.19/0012-surface-gpe.patch new file mode 100644 index 0000000000..f98667d150 --- /dev/null +++ b/patches/6.19/0012-surface-gpe.patch @@ -0,0 +1,51 @@ +From a3871f3b131eda9f5dfc8534915339bff3700bed Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sun, 12 Mar 2023 01:41:57 +0100 +Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 + +Add the lid GPE used by the Surface Pro 9. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe +--- + drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index b359413903b1..b4496db79f39 100644 +--- a/drivers/platform/surface/surface_gpe.c ++++ b/drivers/platform/surface/surface_gpe.c +@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; ++ + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +-- +2.53.0 + diff --git a/patches/6.19/0013-cameras.patch b/patches/6.19/0013-cameras.patch new file mode 100644 index 0000000000..4c02aee311 --- /dev/null +++ b/patches/6.19/0013-cameras.patch @@ -0,0 +1,1019 @@ +From 11bafd85c10d84fbabd327c0dc6fb3dd6f16ba19 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 10 Oct 2021 20:56:57 +0200 +Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an + INT3472 device + +The clk and regulator frameworks expect clk/regulator consumer-devices +to have info about the consumed clks/regulators described in the device's +fw_node. + +To work around cases where this info is not present in the firmware tables, +which is often the case on x86/ACPI devices, both frameworks allow the +provider-driver to attach info about consumers to the clks/regulators +when registering these. + +This causes problems with the probe ordering wrt drivers for consumers +of these clks/regulators. Since the lookups are only registered when the +provider-driver binds, trying to get these clks/regulators before then +results in a -ENOENT error for clks and a dummy regulator for regulators. + +One case where we hit this issue is camera sensors such as e.g. the OV8865 +sensor found on the Microsoft Surface Go. The sensor uses clks, regulators +and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 +ACPI device. There is special platform code handling this and setting +platform_data with the necessary consumer info on the MFD cells +instantiated for the PMIC under: drivers/platform/x86/intel/int3472. + +For this to work properly the ov8865 driver must not bind to the I2C-client +for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and +clk MFD cells have all been fully setup. + +The OV8865 on the Microsoft Surface Go is just one example, all X86 +devices using the Intel IPU3 camera block found on recent Intel SoCs +have similar issues where there is an INT3472 HID ACPI-device, which +describes the clks and regulators, and the driver for this INT3472 device +must be fully initialized before the sensor driver (any sensor driver) +binds for things to work properly. + +On these devices the ACPI nodes describing the sensors all have a _DEP +dependency on the matching INT3472 ACPI device (there is one per sensor). + +This allows solving the probe-ordering problem by delaying the enumeration +(instantiation of the I2C-client in the ov8865 example) of ACPI-devices +which have a _DEP dependency on an INT3472 device. + +The new acpi_dev_ready_for_enumeration() helper used for this is also +exported because for devices, which have the enumeration_by_parent flag +set, the parent-driver will do its own scan of child ACPI devices and +it will try to enumerate those during its probe(). Code doing this such +as e.g. the i2c-core-acpi.c code must call this new helper to ensure +that it too delays the enumeration until all the _DEP dependencies are +met on devices which have the new honor_deps flag set. + +Signed-off-by: Hans de Goede +Patchset: cameras +--- + drivers/acpi/scan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 416d87f9bd10..ce740ec99863 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, + + static void acpi_default_enumeration(struct acpi_device *device) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. +-- +2.53.0 + +From 56075a65d86fcbd501c34548e8bb0e717cea243e Mon Sep 17 00:00:00 2001 +From: zouxiaoh +Date: Fri, 25 Jun 2021 08:52:59 +0800 +Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs + +Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, +The IPU driver allocates its own page table that is not mapped +via the DMA, and thus the Intel IOMMU driver blocks access giving +this error: DMAR: DRHD: handling fault status reg 3 DMAR: +[DMA Read] Request device [00:05.0] PASID ffffffff +fault addr 76406000 [fault reason 06] PTE Read access is not set +As IPU is not an external facing device which is not risky, so use +IOMMU passthrough mode for Intel IPUs. + +Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b +Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 +Tracked-On: #JIITL8-411 +Signed-off-by: Bingbu Cao +Signed-off-by: zouxiaoh +Signed-off-by: Xu Chongyang +Patchset: cameras +--- + drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 09d031bc873f..757208a8e370 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -44,6 +44,13 @@ + ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ + ) + ++#define IS_INTEL_IPU(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9a19 || \ ++ (pdev)->device == 0x9a39 || \ ++ (pdev)->device == 0x4e19 || \ ++ (pdev)->device == 0x465d || \ ++ (pdev)->device == 0x1919)) ++ + #define IOAPIC_RANGE_START (0xfee00000) + #define IOAPIC_RANGE_END (0xfeefffff) + #define IOVA_START_ADDR (0x1000) +@@ -208,12 +215,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + static int dmar_map_ipts = 1; ++static int dmar_map_ipu = 1; + static int intel_iommu_superpage = 1; + static int iommu_identity_mapping; + static int iommu_skip_te_disable; + static int disable_igfx_iommu; + + #define IDENTMAP_AZALIA 4 ++#define IDENTMAP_IPU 8 + #define IDENTMAP_IPTS 16 + + const struct iommu_ops intel_iommu_ops; +@@ -1409,6 +1418,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) + return IOMMU_DOMAIN_IDENTITY; + ++ if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; ++ + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) + return IOMMU_DOMAIN_IDENTITY; + } +@@ -1701,6 +1713,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + ++ if (!dmar_map_ipu) ++ iommu_identity_mapping |= IDENTMAP_IPU; ++ + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; + +@@ -3949,6 +3964,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; + } + ++static void quirk_iommu_ipu(struct pci_dev *dev) ++{ ++ if (!IS_INTEL_IPU(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for integrated Intel IPU\n"); ++ dmar_map_ipu = 0; ++} ++ + static void quirk_iommu_ipts(struct pci_dev *dev) + { + if (!IS_IPTS(dev)) +@@ -3999,6 +4026,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); + ++/* disable IPU dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); ++ + /* disable IPTS dmar support */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); +-- +2.53.0 + +From 998402c80cb2ab636207e1e01d1885bdbbbfaf69 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Sun, 10 Oct 2021 20:57:02 +0200 +Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain + +The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic +can be forwarded to a device connected to the PMIC as though it were +connected directly to the system bus. Enable this mode when the chip +is initialised. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 0133405697dc..9e0763bdc758 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } + ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } ++ + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); + + return 0; +-- +2.53.0 + +From 5d74ab9a86f7ea746e7bcf00541eddaec4d4db85 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Tue, 21 Mar 2023 13:45:26 +0000 +Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 + +Update the control ID for the gain control in the ov7251 driver to +V4L2_CID_ANALOGUE_GAIN. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/i2c/ov7251.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 27afc3fc0175..28b192c9a5ec 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_EXPOSURE: + ret = ov7251_set_exposure(ov7251, ctrl->val); + break; +- case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: + ret = ov7251_set_gain(ov7251, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: +@@ -1579,7 +1579,7 @@ static int ov7251_init_ctrls(struct ov7251 *ov7251) + ov7251->exposure = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 32, 1, 32); + ov7251->gain = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, +- V4L2_CID_GAIN, 16, 1023, 1, 16); ++ V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 16); + v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7251_test_pattern_menu) - 1, +-- +2.53.0 + +From 3ccb6e791a14beda5ecf46b1ff6bc1567f2c9eb7 Mon Sep 17 00:00:00 2001 +From: Daniel Scally +Date: Wed, 22 Mar 2023 11:01:42 +0000 +Subject: [PATCH] media: v4l2-core: Acquire privacy led in + v4l2_async_register_subdev() + +The current call to v4l2_subdev_get_privacy_led() is contained in +v4l2_async_register_subdev_sensor(), but that function isn't used by +all the sensor drivers. Move the acquisition of the privacy led to +v4l2_async_register_subdev() instead. + +Signed-off-by: Daniel Scally +Patchset: cameras +--- + drivers/media/v4l2-core/v4l2-async.c | 4 ++++ + drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c +index ee884a8221fb..4f6bafd900ee 100644 +--- a/drivers/media/v4l2-core/v4l2-async.c ++++ b/drivers/media/v4l2-core/v4l2-async.c +@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) + + INIT_LIST_HEAD(&sd->asc_list); + ++ ret = v4l2_subdev_get_privacy_led(sd); ++ if (ret < 0) ++ return ret; ++ + /* + * No reference taken. The reference is held by the device (struct + * v4l2_subdev.dev), and async sub-device does not exist independently +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index cb153ce42c45..f11b499e14bb 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + + v4l2_async_subdev_nf_init(notifier, sd); + +- ret = v4l2_subdev_get_privacy_led(sd); +- if (ret < 0) +- goto out_cleanup; +- + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); + if (ret < 0) + goto out_cleanup; +-- +2.53.0 + +From 7125994d148d732de64f0dfede3dad68958bcd19 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:16 +0800 +Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED + +Add MFD cell for tps68470-led. + +Reviewed-by: Daniel Scally +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 9e0763bdc758..0976b267972b 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 + +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 + + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -203,7 +203,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; + + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +-- +2.53.0 + +From 9743d4b7ae82c9942549a183d4f48b135a52b324 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:17 +0800 +Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB + +Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB +(TPS68470_ILEDCTL_ENB), and current control mask for LEDB +(TPS68470_ILEDCTL_CTRLB) + +Reviewed-by: Daniel Scally +Reviewed-by: Hans de Goede +Signed-off-by: Kate Hsuan +Patchset: cameras +--- + include/linux/mfd/tps68470.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329db0..2d2abb25b944 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +-- +2.53.0 + +From 437b2a4533778de6d361f397da107cc9b4982d0d Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Tue, 21 Mar 2023 23:37:18 +0800 +Subject: [PATCH] leds: tps68470: Add LED control for tps68470 + +There are two LED controllers, LEDA indicator LED and LEDB flash LED for +tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, +tps68470 provides four levels of power status for LEDB. If the +properties called "ti,ledb-current" can be found, the current will be +set according to the property values. These two LEDs can be controlled +through the LED class of sysfs (tps68470-leda and tps68470-ledb). + +Signed-off-by: Kate Hsuan +Reviewed-by: Hans de Goede +Patchset: cameras +--- + drivers/leds/Kconfig | 12 +++ + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 drivers/leds/leds-tps68470.c + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 11e7282dc297..c5665bd5e522 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -998,6 +998,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. + ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. ++ ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index 9a0333ec1a86..4e1ca8fc9b41 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_UPBOARD) += leds-upboard.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o +diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c +new file mode 100644 +index 000000000000..35aeb5db89c8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ } ++ return -EINVAL; ++} ++ ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; ++ } ++ ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) ++{ ++ int ret = 0; ++ unsigned int curr; ++ ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; ++} ++ ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; ++ ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); +-- +2.53.0 + +From 59e06c991c522d4ded28c1f9a5b901df53b7c4df Mon Sep 17 00:00:00 2001 +From: mojyack +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index 59558335989e..b89765521af5 100644 +--- a/drivers/media/i2c/dw9719.c ++++ b/drivers/media/i2c/dw9719.c +@@ -121,6 +121,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* + * Need 100us to transition from SHUTDOWN to STANDBY. + * Jiggle the SCL pin to wake up the device (even when the regulator is +-- +2.53.0 + +From 800e119032793baa8a62173144ddc79d221a75e2 Mon Sep 17 00:00:00 2001 +From: Tooraj Taraz +Date: Wed, 31 Dec 2025 00:35:50 +0100 +Subject: [PATCH] Add camera support for Surface Pro 9 + +Experimental camera support for the Surface Pro 9. + +Link: https://github.com/linux-surface/linux-surface/pull/1867 +Patchset: cameras +--- + drivers/media/i2c/ov13858.c | 158 +++++++++++++++++- + drivers/media/i2c/ov5693.c | 1 + + drivers/media/pci/intel/ipu-bridge.c | 4 + + drivers/platform/x86/intel/int3472/discrete.c | 23 +++ + 4 files changed, 184 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c +index 162b49046990..85cd0c98af03 100644 +--- a/drivers/media/i2c/ov13858.c ++++ b/drivers/media/i2c/ov13858.c +@@ -2,6 +2,7 @@ + // Copyright (c) 2017 Intel Corporation. + + #include ++#include + #include + #include + #include +@@ -119,6 +120,14 @@ struct ov13858_mode { + struct ov13858_reg_list reg_list; + }; + ++// Or use standard names that might be more correct: ++static const char * const ov13858_supply_names[] = { ++ "avdd", // Analog voltage ++ "pwr1", // Digital core voltage ++}; ++ ++#define OV13858_NUM_SUPPLIES ARRAY_SIZE(ov13858_supply_names) ++ + /* 4224x3136 needs 1080Mbps/lane, 4 lanes */ + static const struct ov13858_reg mipi_data_rate_1080mbps[] = { + /* PLL1 registers */ +@@ -1046,12 +1055,126 @@ struct ov13858 { + /* Current mode */ + const struct ov13858_mode *cur_mode; + ++ struct regulator_bulk_data supplies[OV13858_NUM_SUPPLIES]; ++ struct gpio_desc *reset; ++ struct clk *xvclk; ++ + /* Mutex for serialized access */ + struct mutex mutex; + }; + + #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) + ++ ++static int ov13858_get_regulators(struct ov13858 *ov13858) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < OV13858_NUM_SUPPLIES; i++) ++ ov13858->supplies[i].supply = ov13858_supply_names[i]; ++ ++ return devm_regulator_bulk_get(ov13858->dev, OV13858_NUM_SUPPLIES, ++ ov13858->supplies); ++} ++ ++static int ov13858_sensor_powerup(struct ov13858 *ov13858) ++{ ++ int ret; ++ ++ dev_info(ov13858->dev, "Powering up sensor\n"); ++ ++ /* Assert reset */ ++ gpiod_set_value_cansleep(ov13858->reset, 1); ++ ++ /* Enable clock FIRST - sensor needs clock to communicate */ ++ ret = clk_prepare_enable(ov13858->xvclk); ++ if (ret) { ++ dev_err(ov13858->dev, "Failed to enable clock: %d\n", ret); ++ return ret; ++ } ++ dev_info(ov13858->dev, "Clock enabled\n"); ++ ++ /* Enable regulators */ ++ ret = regulator_bulk_enable(OV13858_NUM_SUPPLIES, ov13858->supplies); ++ if (ret) { ++ dev_err(ov13858->dev, "Failed to enable regulators: %d\n", ret); ++ clk_disable_unprepare(ov13858->xvclk); ++ return ret; ++ } ++ ++ dev_info(ov13858->dev, "Regulators enabled\n"); ++ ++ /* Wait for power to stabilize */ ++ usleep_range(5000, 10000); ++ ++ /* De-assert reset */ ++ gpiod_set_value_cansleep(ov13858->reset, 0); ++ ++ /* Wait for sensor to boot */ ++ msleep(20); ++ ++ dev_info(ov13858->dev, "Reset de-asserted, sensor should be ready\n"); ++ ++ return 0; ++} ++ ++static void ov13858_sensor_powerdown(struct ov13858 *ov13858) ++{ ++ dev_info(ov13858->dev, "Powering down sensor\n"); ++ ++ /* Assert reset to put sensor in reset state */ ++ gpiod_set_value_cansleep(ov13858->reset, 1); ++ ++ /* Disable regulators */ ++ regulator_bulk_disable(OV13858_NUM_SUPPLIES, ov13858->supplies); ++ dev_info(ov13858->dev, "Regulators disabled\n"); ++ ++ /* Disable clock */ ++ clk_disable_unprepare(ov13858->xvclk); ++ dev_info(ov13858->dev, "Clock disabled\n"); ++} ++ ++static int __maybe_unused ov13858_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov13858 *ov13858 = to_ov13858(sd); ++ ++ ov13858_sensor_powerdown(ov13858); ++ ++ return 0; ++} ++ ++static int __maybe_unused ov13858_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov13858 *ov13858 = to_ov13858(sd); ++ int ret; ++ ++ ret = ov13858_sensor_powerup(ov13858); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ov13858_pm_ops = { ++ SET_RUNTIME_PM_OPS(ov13858_suspend, ov13858_resume, NULL) ++}; ++ ++static int ov13858_get_gpios(struct ov13858 *ov13858) ++{ ++ ov13858->reset = devm_gpiod_get_optional(ov13858->dev, "reset", ++ GPIOD_OUT_HIGH); ++ if (IS_ERR(ov13858->reset)) { ++ dev_err(ov13858->dev, "Error fetching reset GPIO\n"); ++ return PTR_ERR(ov13858->reset); ++ } ++ ++ return 0; ++} ++ + /* Read registers up to 4 at a time */ + static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, + u32 *val) +@@ -1498,8 +1621,11 @@ static int ov13858_identify_module(struct ov13858 *ov13858) + int ret; + u32 val; + ++ dev_info(ov13858->dev, "Attempting to read chip ID from register 0x300a\n"); + ret = ov13858_read_reg(ov13858, OV13858_REG_CHIP_ID, + OV13858_REG_VALUE_24BIT, &val); ++ dev_info(ov13858->dev, "Chip ID read result: ret=%d, val=0x%06x (expected 0x%06x)\n", ++ ret, val, OV13858_CHIP_ID); + if (ret) + return ret; + +@@ -1509,6 +1635,7 @@ static int ov13858_identify_module(struct ov13858 *ov13858) + return -EIO; + } + ++ dev_info(ov13858->dev, "Chip ID verified successfully!\n"); + return 0; + } + +@@ -1678,14 +1805,33 @@ static int ov13858_probe(struct i2c_client *client) + "external clock %lu is not supported\n", + freq); + ++ /* Get the external clock */ ++ ov13858->xvclk = devm_clk_get_optional(ov13858->dev, "xvclk"); ++ if (IS_ERR(ov13858->xvclk)) ++ return dev_err_probe(ov13858->dev, PTR_ERR(ov13858->xvclk), ++ "failed to get xvclk\n"); ++ + /* Initialize subdev */ + v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops); + ++ ret = ov13858_get_regulators(ov13858); ++ if (ret) ++ return dev_err_probe(ov13858->dev, ret, ++ "Error fetching regulators\n"); ++ ++ ret = ov13858_get_gpios(ov13858); ++ if (ret) ++ return ret; ++ ++ ret = ov13858_sensor_powerup(ov13858); ++ if (ret) ++ return ret; // No cleanup needed yet, devm handles GPIOs/regulators ++ + /* Check module identity */ + ret = ov13858_identify_module(ov13858); + if (ret) { + dev_err(ov13858->dev, "failed to find sensor: %d\n", ret); +- return ret; ++ goto error_power_off; // Now we need to power down + } + + /* Set default mode to max resolution */ +@@ -1693,7 +1839,7 @@ static int ov13858_probe(struct i2c_client *client) + + ret = ov13858_init_controls(ov13858); + if (ret) +- return ret; ++ goto error_power_off; + + /* Initialize subdev */ + ov13858->sd.internal_ops = &ov13858_internal_ops; +@@ -1729,6 +1875,10 @@ static int ov13858_probe(struct i2c_client *client) + + error_handler_free: + ov13858_free_controls(ov13858); ++ ++error_power_off: ++ ov13858_sensor_powerdown(ov13858); ++ + dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret); + + return ret; +@@ -1744,6 +1894,9 @@ static void ov13858_remove(struct i2c_client *client) + ov13858_free_controls(ov13858); + + pm_runtime_disable(ov13858->dev); ++ if (!pm_runtime_status_suspended(ov13858->dev)) ++ ov13858_sensor_powerdown(ov13858); ++ pm_runtime_set_suspended(ov13858->dev); + } + + static const struct i2c_device_id ov13858_id_table[] = { +@@ -1765,6 +1918,7 @@ MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids); + static struct i2c_driver ov13858_i2c_driver = { + .driver = { + .name = "ov13858", ++ .pm = &ov13858_pm_ops, + .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), + }, + .probe = ov13858_probe, +diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c +index 4cc796bbee92..02236f3db19d 100644 +--- a/drivers/media/i2c/ov5693.c ++++ b/drivers/media/i2c/ov5693.c +@@ -1396,6 +1396,7 @@ static const struct dev_pm_ops ov5693_pm_ops = { + + static const struct acpi_device_id ov5693_acpi_match[] = { + {"INT33BE"}, ++ {"OVTI5693"}, + {}, + }; + MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +index b2b710094914..f5456330bbc9 100644 +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -61,6 +61,10 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { + IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), + /* Onsemi MT9M114 */ + IPU_SENSOR_CONFIG("INT33F0", 1, 384000000), ++ /* Omnivision OV5693 - Surface Pro 9 */ ++ IPU_SENSOR_CONFIG("OVTI5693", 1, 419200000), ++ /* Omnivision OV13858 - Surface Pro 9 */ ++ IPU_SENSOR_CONFIG("OVTID858", 4, 540000000), + /* Omnivision OV2740 */ + IPU_SENSOR_CONFIG("INT3474", 1, 180000000), + /* Omnivision OV5670 */ +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index 1505fc3ef7a8..20962e8acb26 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -229,6 +229,14 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 + /* Setups using a handshake pin need 25 ms enable delay */ + *enable_time_us = 25 * USEC_PER_MSEC; + break; ++ case 0x08: /* Surface Pro 9 - additional power rail */ ++ *con_id = "pwr1"; ++ *gpio_flags = GPIO_ACTIVE_HIGH; ++ break; ++ case 0x10: /* Surface Pro 9 - secondary power rail */ ++ *con_id = "pwr2"; ++ *gpio_flags = GPIO_ACTIVE_HIGH; ++ break; + default: + *con_id = "unknown"; + *gpio_flags = GPIO_ACTIVE_HIGH; +@@ -333,6 +341,8 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, + case INT3472_GPIO_TYPE_PRIVACY_LED: + case INT3472_GPIO_TYPE_POWER_ENABLE: + case INT3472_GPIO_TYPE_HANDSHAKE: ++ case 0x08: /* Surface Pro 9 power rails */ ++ case 0x10: + gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); + if (IS_ERR(gpio)) { + ret = PTR_ERR(gpio); +@@ -363,6 +373,19 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, + err_msg = "Failed to register regulator\n"; + + break; ++ case 0x08: /* Surface Pro 9 - treat as power*/ ++ dev_info(int3472->dev, "GPIO type 0x%02x detected on pin 0x%02x\n", type, agpio->pin_table[0]); ++ dev_info(int3472->dev, " con_id=%s, flags=0x%x\n", con_id, gpio_flags); ++ ret = skl_int3472_register_regulator(int3472, gpio, ++ GPIO_REGULATOR_ENABLE_TIME, ++ con_id, NULL); ++ dev_info(int3472->dev, " register_regulator returned: %d\n", ret); ++ if (ret) { ++ dev_err(int3472->dev, "Failed to register type 0x02x: %d\n", type, ret); ++ } ++ break; ++ case 0x10: ++ break; + default: /* Never reached */ + ret = -EINVAL; + break; +-- +2.53.0 + diff --git a/patches/6.19/0014-amd-gpio.patch b/patches/6.19/0014-amd-gpio.patch new file mode 100644 index 0000000000..8e245a57a4 --- /dev/null +++ b/patches/6.19/0014-amd-gpio.patch @@ -0,0 +1,109 @@ +From d97bb3ff6090aa36907b602f41fe706968b1c6d4 Mon Sep 17 00:00:00 2001 +From: Sachi King +Date: Sat, 29 May 2021 17:47:38 +1000 +Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 + override + +This patch is the work of Thomas Gleixner and is +copied from: +https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ + +This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin +setup that is missing in the laptops ACPI table. + +This patch was used for validation of the issue, and is not a proper +fix, but is probably a better temporary hack than continuing to probe +the Legacy PIC and run with the PIC in an unknown state. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 9fa321a95eb3..8914a922be2b 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1171,6 +1172,17 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") ++ }, ++ }, ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1227,6 +1239,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, + acpi_gbl_FADT.sci_interrupt); + ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } ++ + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); + +-- +2.53.0 + +From 3dba74f758f1ba60e5ccc3bf62fc20b116716555 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Thu, 3 Jun 2021 14:04:26 +0200 +Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override + quirk + +The 13" version of the Surface Laptop 4 has the same problem as the 15" +version, but uses a different SKU. Add that SKU to the quirk as well. + +Patchset: amd-gpio +--- + arch/x86/kernel/acpi/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 8914a922be2b..c43d0a553867 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) + + static const struct dmi_system_id surface_quirk[] __initconst = { + { +- .ident = "Microsoft Surface Laptop 4 (AMD)", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, + }, ++ { ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") ++ }, ++ }, + {} + }; + +-- +2.53.0 + diff --git a/patches/6.19/0015-rtc.patch b/patches/6.19/0015-rtc.patch new file mode 100644 index 0000000000..7d699c3a46 --- /dev/null +++ b/patches/6.19/0015-rtc.patch @@ -0,0 +1,111 @@ +From 637e1e0d2226b877d44666f60dbe1998ad509c03 Mon Sep 17 00:00:00 2001 +From: "Bart Groeneveld | GPX Solutions B.V" +Date: Mon, 5 Dec 2022 16:08:46 +0100 +Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms + +The specification [1] allows so-called HW-reduced platforms, +which do not implement everything, especially the wakeup related stuff. + +In that case, it is still usable as a RTC. This is helpful for [2] +and [3], which is about a device with no other working RTC, +but it does have an HW-reduced TAD, which can be used as a RTC instead. + +[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device +[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 +[3]: https://github.com/linux-surface/linux-surface/issues/415 + +Signed-off-by: Bart Groeneveld | GPX Solutions B.V. +Patchset: rtc +--- + drivers/acpi/acpi_tad.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index 6d870d97ada6..a19cd08e1554 100644 +--- a/drivers/acpi/acpi_tad.c ++++ b/drivers/acpi/acpi_tad.c +@@ -438,6 +438,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(caps); + ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -486,15 +494,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RW(ac_status); + +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -571,14 +578,19 @@ static void acpi_tad_remove(struct platform_device *pdev) + if (dd->capabilities & ACPI_TAD_RT) + sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); + + scoped_guard(pm_runtime_noresume, dev) { +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); +@@ -621,12 +633,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + goto remove_handler; + } + +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- ret = -ENODEV; +- goto remove_handler; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) { + ret = -ENOMEM; +@@ -657,6 +663,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; + ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +-- +2.53.0 + diff --git a/patches/6.19/0016-hid-surface.patch b/patches/6.19/0016-hid-surface.patch new file mode 100644 index 0000000000..4fcf1d3899 --- /dev/null +++ b/patches/6.19/0016-hid-surface.patch @@ -0,0 +1,246 @@ +From 8de1717f5eafe891c12671c2a2bc35424658b45c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= +Date: Fri, 10 Oct 2025 19:04:03 +0100 +Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) + +The Surface Aggregator Module firmware incorrectly reports the FN key +as BTN_0 (button 256) through runtime HID events. This button can get +stuck in pressed state, flooding the input system and breaking focus +tracking in KWin Wayland compositor. + +Add a new hid-surface driver that filters BTN_0 events using the event +callback. The FN key should be handled as a hardware modifier and not +reported to the OS. + +Tested on Surface Laptop 4 AMD with KDE Plasma Wayland. After the fix: +- FN key combinations work correctly (volume, brightness) +- Focus tracking no longer breaks +- Mouse clicks work on all windows + +Fixes: https://github.com/linux-surface/linux-surface/issues/1851 +Patchset: hid-surface +--- + drivers/hid/Kconfig | 8 ++++ + drivers/hid/Makefile | 1 + + drivers/hid/hid-surface.c | 90 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 99 insertions(+) + create mode 100644 drivers/hid/hid-surface.c + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 59d597b4effd..d59290a9388e 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1142,6 +1142,14 @@ config HID_SUNPLUS + help + Support for Sunplus wireless desktop. + ++config HID_SURFACE ++ tristate "Microsoft Surface" ++ depends on SURFACE_AGGREGATOR ++ help ++ Say Y here to enable HID driver for Microsoft Surface integrated ++ keyboard and touchpad. This driver filters out erroneous BTN_0 ++ (FN key) events that can cause input focus issues. ++ + config HID_RMI + tristate "Synaptics RMI4 device support" + select RMI4_CORE +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 3190ece25626..4d2891879548 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -174,6 +174,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++obj-$(CONFIG_HID_SURFACE) += hid-surface.o + + obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ + +diff --git a/drivers/hid/hid-surface.c b/drivers/hid/hid-surface.c +new file mode 100644 +index 000000000000..a171ea65672f +--- /dev/null ++++ b/drivers/hid/hid-surface.c +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * HID driver for Microsoft Surface devices ++ * ++ * Copyright (c) 2025 Linux Surface Project ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++/* ++ * The Surface Aggregator Module firmware incorrectly reports the FN key ++ * as BTN_0 (button 256). This button can get stuck in pressed state, ++ * flooding the input system and breaking focus tracking in some ++ * compositors. Filter out BTN_0 as FN should be handled as a hardware ++ * modifier, not reported to the OS. ++ */ ++static int surface_input_mapping(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ /* ++ * Filter BTN_0 during input mapping in case it appears in the ++ * HID descriptor (defense in depth). ++ */ ++ if (usage->type == EV_KEY && usage->code == BTN_0) ++ return -1; /* Don't map this usage */ ++ ++ return 0; /* Use default mapping */ ++} ++ ++static int surface_event(struct hid_device *hdev, struct hid_field *field, ++ struct hid_usage *usage, __s32 value) ++{ ++ /* ++ * The Surface Aggregator Module firmware reports the FN key as BTN_0 ++ * at runtime. This button can get stuck in pressed state, flooding ++ * the input system and breaking focus tracking. Filter out these ++ * events as FN should be a hardware modifier, not reported to the OS. ++ */ ++ if (usage->type == EV_KEY && usage->code == BTN_0) ++ return 1; /* Event handled, don't process further */ ++ ++ return 0; /* Process event normally */ ++} ++ ++static int surface_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ int ret; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "parse failed\n"); ++ return ret; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ++ if (ret) { ++ hid_err(hdev, "hw start failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct hid_device_id surface_devices[] = { ++ { HID_DEVICE(BUS_HOST, HID_GROUP_GENERIC, ++ USB_VENDOR_ID_MICROSOFT, 0x09AE) }, /* Surface Keyboard */ ++ { HID_DEVICE(BUS_HOST, HID_GROUP_GENERIC, ++ USB_VENDOR_ID_MICROSOFT, 0x09AF) }, /* Surface Mouse/Touchpad */ ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, surface_devices); ++ ++static struct hid_driver surface_driver = { ++ .name = "surface", ++ .id_table = surface_devices, ++ .probe = surface_probe, ++ .input_mapping = surface_input_mapping, ++ .event = surface_event, ++}; ++module_hid_driver(surface_driver); ++ ++MODULE_AUTHOR("Linux Surface Project"); ++MODULE_DESCRIPTION("Microsoft Surface HID driver"); ++MODULE_LICENSE("GPL"); +-- +2.53.0 + +From de9b50c2e866713da82ecd3856216a7c3ff5dce4 Mon Sep 17 00:00:00 2001 +From: LegendaryFire +Date: Wed, 24 Dec 2025 00:54:44 -0800 +Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 + touch pad + +Patchset: hid-surface +--- + drivers/hid/hid-multitouch.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index bd2554f2127f..973f55f23ddf 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) + #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) ++#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(26) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 +@@ -244,6 +245,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); + #define MT_CLS_SMART_TECH 0x0113 + #define MT_CLS_APPLE_TOUCHBAR 0x0114 + #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 ++#define MT_CLS_SURFACE_TOUCHPAD 0x0116 + #define MT_CLS_SIS 0x0457 + + #define MT_DEFAULT_MAXCONTACT 10 +@@ -452,6 +454,10 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_WIN8_PTP_BUTTONS, + .export_all_inputs = true + }, ++ { .name = MT_CLS_SURFACE_TOUCHPAD, ++ .quirks = MT_QUIRK_ALWAYS_VALID | ++ MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE ++ }, + { } + }; + +@@ -2191,11 +2197,30 @@ static void mt_remove(struct hid_device *hdev) + + static void mt_on_hid_hw_open(struct hid_device *hdev) + { ++ /* ++ * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck ++ * non-functional if we change touchpad reporting modes from the HID ++ * open/close hooks. Avoid mode switching on hw_open/hw_close for ++ * those devices. ++ */ ++ struct mt_device *td = hid_get_drvdata(hdev); ++ if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) ++ return; + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + } + + static void mt_on_hid_hw_close(struct hid_device *hdev) + { ++ /* ++ * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck ++ * non-functional if we change touchpad reporting modes from the HID ++ * open/close hooks. Avoid mode switching on hw_open/hw_close for ++ * those devices. ++ */ ++ struct mt_device *td = hid_get_drvdata(hdev); ++ if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) ++ return; ++ + mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); + } + +@@ -2632,6 +2657,11 @@ static const struct hid_device_id mt_devices[] = { + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, + USB_VENDOR_ID_MICROSOFT, 0x09c0) }, + ++ /* Microsoft Surface touch pad */ ++ { .driver_data = MT_CLS_SURFACE_TOUCHPAD, ++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, ++ USB_VENDOR_ID_MICROSOFT, 0x0C46) }, ++ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, +-- +2.53.0 + diff --git a/patches/6.19/0017-powercap.patch b/patches/6.19/0017-powercap.patch new file mode 100644 index 0000000000..4c8a188334 --- /dev/null +++ b/patches/6.19/0017-powercap.patch @@ -0,0 +1,30 @@ +From ce7514b67d4a0481bbc29536ce468c679679dbe6 Mon Sep 17 00:00:00 2001 +From: Daniel Tang +Date: Wed, 14 Jan 2026 20:31:38 -0500 +Subject: [PATCH] powercap: intel_rapl: Add PL4 support for Ice Lake + +Microsoft Surface Pro 7 firmware throttles the processor upon +boot/resume. Userspace needs to be able to restore the correct value. + +Link: https://github.com/linux-surface/linux-surface/issues/706 +Signed-off-by: Daniel Tang +Patchset: powercap +--- + drivers/powercap/intel_rapl_msr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c +index 9a7e150b3536..a2bc0a9c1e10 100644 +--- a/drivers/powercap/intel_rapl_msr.c ++++ b/drivers/powercap/intel_rapl_msr.c +@@ -162,6 +162,7 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra) + + /* List of verified CPUs. */ + static const struct x86_cpu_id pl4_support_ids[] = { ++ X86_MATCH_VFM(INTEL_ICELAKE_L, NULL), + X86_MATCH_VFM(INTEL_TIGERLAKE_L, NULL), + X86_MATCH_VFM(INTEL_ALDERLAKE, NULL), + X86_MATCH_VFM(INTEL_ALDERLAKE_L, NULL), +-- +2.53.0 + From d0bd7ce5b920b06c60a6bf50e932e031a64ef6b1 Mon Sep 17 00:00:00 2001 From: Cornell Chin Date: Wed, 4 Mar 2026 16:04:12 -0500 Subject: [PATCH 210/236] Update v6.19 patches Changes: - Rebase onto v6.19.6 --- patches/6.19/0001-secureboot.patch | 4 +- patches/6.19/0002-surface3.patch | 4 +- patches/6.19/0003-mwifiex.patch | 10 +-- patches/6.19/0004-ath10k.patch | 2 +- patches/6.19/0005-ipts.patch | 20 ++--- patches/6.19/0006-ithc.patch | 8 +- patches/6.19/0007-surface-sam.patch | 8 +- patches/6.19/0008-surface-sam-over-hid.patch | 4 +- patches/6.19/0009-surface-button.patch | 4 +- patches/6.19/0010-surface-typecover.patch | 78 ++++++++++---------- patches/6.19/0011-surface-shutdown.patch | 20 ++--- patches/6.19/0012-surface-gpe.patch | 2 +- patches/6.19/0013-cameras.patch | 38 +++++----- patches/6.19/0014-amd-gpio.patch | 14 ++-- patches/6.19/0015-rtc.patch | 2 +- patches/6.19/0016-hid-surface.patch | 34 ++++----- patches/6.19/0017-powercap.patch | 30 -------- 17 files changed, 126 insertions(+), 156 deletions(-) delete mode 100644 patches/6.19/0017-powercap.patch diff --git a/patches/6.19/0001-secureboot.patch b/patches/6.19/0001-secureboot.patch index 9d7e332c2d..fced69f3a9 100644 --- a/patches/6.19/0001-secureboot.patch +++ b/patches/6.19/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 11f4a85c1156171c22e03216d13384bec651541e Mon Sep 17 00:00:00 2001 +From 5e70f3948db99688eec0b82295617fb08f66e9fc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 -- 2.53.0 -From 1e091139669d3d03f3abf3106ed2fabda98082bb Mon Sep 17 00:00:00 2001 +From 26de633ca6c52842f679f381897ed4f69b5c1aa6 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.19/0002-surface3.patch b/patches/6.19/0002-surface3.patch index 3392efd0d9..f5d71995c3 100644 --- a/patches/6.19/0002-surface3.patch +++ b/patches/6.19/0002-surface3.patch @@ -1,4 +1,4 @@ -From 15ab9b53834ba0ab25433ecfc02ee1659b2ff95b Mon Sep 17 00:00:00 2001 +From 9f9b1fbb2f62082827262f5aa1a1ce6e40624639 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.53.0 -From c881590fdf25571ca9576ddb5fb1672092cd458a Mon Sep 17 00:00:00 2001 +From dc1bcef8cef69cf7eceaa07ffd74dc957fcfb335 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.19/0003-mwifiex.patch b/patches/6.19/0003-mwifiex.patch index 01d6126b41..57940221d4 100644 --- a/patches/6.19/0003-mwifiex.patch +++ b/patches/6.19/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 5c32be551d5e372447cc2f4faae21d20a07ae94e Mon Sep 17 00:00:00 2001 +From 04f816e7f96dc829e15c324812ef93d7af9b08ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.53.0 -From e4b75eaf26d9ffaa19c85875a8b6604783500e38 Mon Sep 17 00:00:00 2001 +From b406ec8c7d68bbc4c571672324247c8cd37de533 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.53.0 -From a15b4cd04c9904f36e0124d3175fa4daeeb1269b Mon Sep 17 00:00:00 2001 +From 6d158290073b93a10b5f62ad0db9e764d5f04ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 80ccfa8fd982..093e17983eb7 100644 +index a41bb1e2a279..572a9bcd2484 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; @@ -375,7 +375,7 @@ index 80ccfa8fd982..093e17983eb7 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4229,6 +4231,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4236,6 +4238,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; diff --git a/patches/6.19/0004-ath10k.patch b/patches/6.19/0004-ath10k.patch index fc327230a9..bd668aeb77 100644 --- a/patches/6.19/0004-ath10k.patch +++ b/patches/6.19/0004-ath10k.patch @@ -1,4 +1,4 @@ -From e5e36c49ec4ebd249eb220fa0028f57f1db3dc25 Mon Sep 17 00:00:00 2001 +From e99f630d657295b9f6d12c6f61a3d208f392e757 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.19/0005-ipts.patch b/patches/6.19/0005-ipts.patch index 8258f7d10c..4e50a30032 100644 --- a/patches/6.19/0005-ipts.patch +++ b/patches/6.19/0005-ipts.patch @@ -1,4 +1,4 @@ -From 6235e3f2891f0162cf07e78fd9a2d11f072d29e3 Mon Sep 17 00:00:00 2001 +From 129296e814686b07a5e6fbdd0411498a90f37e94 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e569558b9..c19dfba542c1 100644 -- 2.53.0 -From 36f2f146cc18cc0185c65637aa7f0d1689bcf4ee Mon Sep 17 00:00:00 2001 +From 9fe94d5f42f186a8110033722d26ce29d40d3685 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 134302fbcd92..09d031bc873f 100644 +index 705828b06e32..1400bf283aa6 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -91,7 +91,7 @@ index 134302fbcd92..09d031bc873f 100644 const struct iommu_ops intel_iommu_ops; -@@ -1401,6 +1408,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1398,6 +1405,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -101,7 +101,7 @@ index 134302fbcd92..09d031bc873f 100644 } return 0; -@@ -1691,6 +1701,9 @@ static int __init init_dmars(void) +@@ -1688,6 +1698,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -111,7 +111,7 @@ index 134302fbcd92..09d031bc873f 100644 check_tylersburg_isoch(); /* -@@ -3936,6 +3949,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -3933,6 +3946,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -130,7 +130,7 @@ index 134302fbcd92..09d031bc873f 100644 /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); -@@ -3974,6 +3999,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -3971,6 +3996,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -144,7 +144,7 @@ index 134302fbcd92..09d031bc873f 100644 -- 2.53.0 -From af52eedf010166a262fae4b5fdd962226a5f0672 Mon Sep 17 00:00:00 2001 +From a08b1047b9f0a392b8089c5d47c49c9acd309072 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,10 +211,10 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 920a64b66b25..314e3b0479be 100644 +index 6ff4a3ad34cb..5d41410ac567 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1442,6 +1442,8 @@ source "drivers/hid/surface-hid/Kconfig" +@@ -1443,6 +1443,8 @@ source "drivers/hid/surface-hid/Kconfig" source "drivers/hid/intel-thc-hid/Kconfig" diff --git a/patches/6.19/0006-ithc.patch b/patches/6.19/0006-ithc.patch index c3bf0ba836..99f850144b 100644 --- a/patches/6.19/0006-ithc.patch +++ b/patches/6.19/0006-ithc.patch @@ -1,4 +1,4 @@ -From 703eeaea6536d65c01c092e5f844a784f2d18df5 Mon Sep 17 00:00:00 2001 +From 48f246ea9cad43b412653cc9b01386bd68f1a333 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9c72..c78806d35f2b 100644 -- 2.53.0 -From 063f50f47ef7f0a0d4466f70b3450dc8335f5f24 Mon Sep 17 00:00:00 2001 +From aad08f7adf72af99b6af60f582c60e40a4d9db16 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,10 +86,10 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 314e3b0479be..59d597b4effd 100644 +index 5d41410ac567..fb65f49b5f65 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1444,6 +1444,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" +@@ -1445,6 +1445,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" source "drivers/hid/ipts/Kconfig" diff --git a/patches/6.19/0007-surface-sam.patch b/patches/6.19/0007-surface-sam.patch index ee42aaea25..77aedd3fa2 100644 --- a/patches/6.19/0007-surface-sam.patch +++ b/patches/6.19/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From ce0fa0a3ecff792f7a9bfdac05d8fa21718a0dff Mon Sep 17 00:00:00 2001 +From 00d5742cf4d64274b9497b950ebc6af16d80f22f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -14,10 +14,10 @@ Patchset: surface-sam create mode 100644 drivers/rtc/rtc-surface.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 50dc779f7f98..63aaff40a0fd 100644 +index 50ba48609d74..c0afe893e8bf 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig -@@ -1423,6 +1423,13 @@ config RTC_DRV_NTXEC +@@ -1424,6 +1424,13 @@ config RTC_DRV_NTXEC embedded controller found in certain e-book readers designed by the original design manufacturer Netronix. @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.53.0 -From 88065461b3da56157ade06b0cbab4b4bf2aa5cac Mon Sep 17 00:00:00 2001 +From 3342129fcc0003ea918230936cf78ba1263e2802 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.19/0008-surface-sam-over-hid.patch b/patches/6.19/0008-surface-sam-over-hid.patch index 969dfce8b5..1bef3f5d34 100644 --- a/patches/6.19/0008-surface-sam-over-hid.patch +++ b/patches/6.19/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 2e4050a5807541e471392dccf9548e88489e70b6 Mon Sep 17 00:00:00 2001 +From 0e63337c09db38b0e44f0a7e841e212538cb52c1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a27b7..070c36637811 100644 -- 2.53.0 -From 179eceb312b4dd735e9665d42637fe1805592412 Mon Sep 17 00:00:00 2001 +From 2dd5dbd39c0ddf1e6c10e50dc481fb753d7a4978 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.19/0009-surface-button.patch b/patches/6.19/0009-surface-button.patch index c11714a232..75fbc12e02 100644 --- a/patches/6.19/0009-surface-button.patch +++ b/patches/6.19/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 93e2e5694855fa7a53c6e465cedf07e18653bd43 Mon Sep 17 00:00:00 2001 +From 7702d0b1c74cce7ffc8f9079f84e94bbca54802c Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.53.0 -From 63462c31da1c67a2a472be398ddc9ceee69ac32c Mon Sep 17 00:00:00 2001 +From fd36767467cd0a6d82445835f8dbd94bc6205668 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.19/0010-surface-typecover.patch b/patches/6.19/0010-surface-typecover.patch index 8f457931dc..6120463709 100644 --- a/patches/6.19/0010-surface-typecover.patch +++ b/patches/6.19/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 65a6164c1eadb5f8ec8ccfa46e6c632ee0de16be Mon Sep 17 00:00:00 2001 +From fc36351b8c297d2662f956222bd18764bb527b14 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c4d85089d19b..3d0d35c72189 100644 -- 2.53.0 -From 5950b1c8141212f47505f566e315858c79f33597 Mon Sep 17 00:00:00 2001 +From a20b815aee102a70b2a64eba357dffd431c294c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index b1c3ef129058..44ac1d672ee9 100644 +index 7daa8f6d8187..2a5c497a519b 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -97,15 +97,15 @@ index b1c3ef129058..44ac1d672ee9 100644 #include "hid-haptic.h" -@@ -76,6 +80,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) +@@ -77,6 +81,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_ORIENTATION_INVERT BIT(22) #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) + #define MT_QUIRK_YOGABOOK9I BIT(24) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -83,6 +88,8 @@ MODULE_LICENSE("GPL"); +@@ -84,6 +89,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_CLICKPAD 0 #define MT_BUTTONTYPE_PRESSUREPAD 1 @@ -114,7 +114,7 @@ index b1c3ef129058..44ac1d672ee9 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -186,6 +193,8 @@ struct mt_device { +@@ -187,6 +194,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -123,17 +123,17 @@ index b1c3ef129058..44ac1d672ee9 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -231,6 +240,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 +@@ -233,6 +242,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_SMART_TECH 0x0113 #define MT_CLS_APPLE_TOUCHBAR 0x0114 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 + #define MT_CLS_YOGABOOK9I 0x0115 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0116 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -428,6 +438,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE, +@@ -438,6 +448,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_YOGABOOK9I, + .export_all_inputs = true }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -148,7 +148,7 @@ index b1c3ef129058..44ac1d672ee9 100644 { } }; -@@ -1853,6 +1873,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1919,6 +1939,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -218,7 +218,7 @@ index b1c3ef129058..44ac1d672ee9 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1881,6 +1964,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1947,6 +2030,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -228,7 +228,7 @@ index b1c3ef129058..44ac1d672ee9 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1919,8 +2005,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1985,8 +2071,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -240,7 +240,7 @@ index b1c3ef129058..44ac1d672ee9 100644 if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && !hid_find_field(hdev, HID_INPUT_REPORT, -@@ -1934,8 +2022,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -2000,8 +2088,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -252,7 +252,7 @@ index b1c3ef129058..44ac1d672ee9 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1996,6 +2086,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -2062,6 +2152,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -260,7 +260,7 @@ index b1c3ef129058..44ac1d672ee9 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2440,6 +2531,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2515,6 +2606,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, @@ -275,7 +275,7 @@ index b1c3ef129058..44ac1d672ee9 100644 -- 2.53.0 -From 07990c05b76076db813df4fefa9451595fb123c5 Mon Sep 17 00:00:00 2001 +From 9c220c6897df451dae5f6463bd98470f26e7eff9 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -304,18 +304,18 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 44ac1d672ee9..bd2554f2127f 100644 +index 2a5c497a519b..0c964cc3f9ce 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -81,6 +81,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) +@@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) + #define MT_QUIRK_YOGABOOK9I BIT(24) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -89,6 +90,8 @@ MODULE_LICENSE("GPL"); +@@ -90,6 +91,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_PRESSUREPAD 1 #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 @@ -324,7 +324,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -440,6 +443,7 @@ static const struct mt_class mt_classes[] = { +@@ -450,6 +453,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -332,7 +332,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1474,6 +1478,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1484,6 +1488,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -342,7 +342,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1501,6 +1508,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1511,6 +1518,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -364,7 +364,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1527,6 +1549,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1537,6 +1559,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -372,7 +372,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1534,6 +1557,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1544,6 +1567,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -392,7 +392,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 /* let hid-core decide for the others */ return 0; } -@@ -1543,11 +1579,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1553,11 +1589,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -414,7 +414,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 return 0; } -@@ -1730,6 +1776,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1772,6 +1818,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -457,7 +457,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1787,6 +1869,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1829,6 +1911,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -471,7 +471,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 default: suffix = "UNKNOWN"; break; -@@ -1873,30 +1962,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1939,30 +2028,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -502,7 +502,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1905,8 +1970,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1971,8 +2036,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -514,7 +514,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -2064,13 +2130,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -2130,13 +2196,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -539,7 +539,7 @@ index 44ac1d672ee9..bd2554f2127f 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -2079,12 +2156,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -2145,12 +2222,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); diff --git a/patches/6.19/0011-surface-shutdown.patch b/patches/6.19/0011-surface-shutdown.patch index b414542211..9236832208 100644 --- a/patches/6.19/0011-surface-shutdown.patch +++ b/patches/6.19/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From f1da140af03cace2df8b9462fe4ce041bf8dd954 Mon Sep 17 00:00:00 2001 +From 9c5dd3345ee05bc2b993585eb66304455a1c53c9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 7c2d9d596258..dc792984c2a7 100644 +index 301a9418e38e..c49bdf52794a 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,10 +37,10 @@ index 7c2d9d596258..dc792984c2a7 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 280cd50d693b..454d1cb23dde 100644 +index fd86f72f54ae..14f03bf95644 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6340,3 +6340,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +@@ -6377,3 +6377,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); #endif @@ -81,10 +81,10 @@ index 280cd50d693b..454d1cb23dde 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index b5cc0c2b9906..9cd35904dafc 100644 +index e958ff744335..2053f33968fb 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -488,6 +488,7 @@ struct pci_dev { +@@ -489,6 +489,7 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ @@ -95,7 +95,7 @@ index b5cc0c2b9906..9cd35904dafc 100644 -- 2.53.0 -From 1fbb5e7dcfcfafc56d810d0c3bb974211fd35c7b Mon Sep 17 00:00:00 2001 +From 196cad19ffd57eed5b267b9c20904f6208388ad4 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops @@ -108,10 +108,10 @@ Patchset: surface-shutdown 1 file changed, 13 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 454d1cb23dde..7d2e7f6572db 100644 +index 14f03bf95644..06b2debf32bf 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6359,6 +6359,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { +@@ -6396,6 +6396,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), }, }, @@ -125,7 +125,7 @@ index 454d1cb23dde..7d2e7f6572db 100644 {} }; -@@ -6376,3 +6383,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thu +@@ -6413,3 +6420,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thu DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/patches/6.19/0012-surface-gpe.patch b/patches/6.19/0012-surface-gpe.patch index f98667d150..d80ed78ce1 100644 --- a/patches/6.19/0012-surface-gpe.patch +++ b/patches/6.19/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From a3871f3b131eda9f5dfc8534915339bff3700bed Mon Sep 17 00:00:00 2001 +From ba43d1d68595eb90cb1a89f303b3ae0d8881c11f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.19/0013-cameras.patch b/patches/6.19/0013-cameras.patch index 4c02aee311..8bb28489b1 100644 --- a/patches/6.19/0013-cameras.patch +++ b/patches/6.19/0013-cameras.patch @@ -1,4 +1,4 @@ -From 11bafd85c10d84fbabd327c0dc6fb3dd6f16ba19 Mon Sep 17 00:00:00 2001 +From ddef27e2262b0aaa2f2e8db5cfd4a26c9fa9767a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,10 +58,10 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 416d87f9bd10..ce740ec99863 100644 +index b78f6be2f946..801171e2a7ff 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c -@@ -2205,6 +2205,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, +@@ -2206,6 +2206,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, static void acpi_default_enumeration(struct acpi_device *device) { @@ -74,7 +74,7 @@ index 416d87f9bd10..ce740ec99863 100644 -- 2.53.0 -From 56075a65d86fcbd501c34548e8bb0e717cea243e Mon Sep 17 00:00:00 2001 +From 9b15e761340a32b556cae410271d474ed218f564 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 09d031bc873f..757208a8e370 100644 +index 1400bf283aa6..cca97e5b276e 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -132,7 +132,7 @@ index 09d031bc873f..757208a8e370 100644 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -1409,6 +1418,9 @@ static int device_def_domain_type(struct device *dev) +@@ -1406,6 +1415,9 @@ static int device_def_domain_type(struct device *dev) if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; @@ -142,7 +142,7 @@ index 09d031bc873f..757208a8e370 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -1701,6 +1713,9 @@ static int __init init_dmars(void) +@@ -1698,6 +1710,9 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); } @@ -152,7 +152,7 @@ index 09d031bc873f..757208a8e370 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -3949,6 +3964,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) +@@ -3946,6 +3961,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) disable_igfx_iommu = 1; } @@ -171,7 +171,7 @@ index 09d031bc873f..757208a8e370 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -3999,6 +4026,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -3996,6 +4023,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx); @@ -184,7 +184,7 @@ index 09d031bc873f..757208a8e370 100644 -- 2.53.0 -From 998402c80cb2ab636207e1e01d1885bdbbbfaf69 Mon Sep 17 00:00:00 2001 +From ff1872c350f3d93ddbc363c92f81b8318303f4e1 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.53.0 -From 5d74ab9a86f7ea746e7bcf00541eddaec4d4db85 Mon Sep 17 00:00:00 2001 +From 63b926d5dafab47d37c4341379146e47680a8619 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0175..28b192c9a5ec 100644 -- 2.53.0 -From 3ccb6e791a14beda5ecf46b1ff6bc1567f2c9eb7 Mon Sep 17 00:00:00 2001 +From 78f2aa76c040b63d91ced0c508ce3f5e824fc7b7 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -279,10 +279,10 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index ee884a8221fb..4f6bafd900ee 100644 +index 1c08bba9ecb9..57a990d7dc84 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c -@@ -799,6 +799,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) +@@ -811,6 +811,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) INIT_LIST_HEAD(&sd->asc_list); @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.53.0 -From 7125994d148d732de64f0dfede3dad68958bcd19 Mon Sep 17 00:00:00 2001 +From 68a76f4000077219ade692d9e02e0bb976ecf476 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.53.0 -From 9743d4b7ae82c9942549a183d4f48b135a52b324 Mon Sep 17 00:00:00 2001 +From d7c13ebfd24661e4255535aa5f9ea2e519e0d385 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.53.0 -From 437b2a4533778de6d361f397da107cc9b4982d0d Mon Sep 17 00:00:00 2001 +From 7214f4920999126ae37ab2bfbd27a92fcbcf5504 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.53.0 -From 59e06c991c522d4ded28c1f9a5b901df53b7c4df Mon Sep 17 00:00:00 2001 +From eb238bac83b853ab4ea7cbf68632bf0e52d54dea Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 59558335989e..b89765521af5 100644 -- 2.53.0 -From 800e119032793baa8a62173144ddc79d221a75e2 Mon Sep 17 00:00:00 2001 +From 535249a26f36e154d83a194593ded787f3c50f40 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.19/0014-amd-gpio.patch b/patches/6.19/0014-amd-gpio.patch index 8e245a57a4..e1b22744f5 100644 --- a/patches/6.19/0014-amd-gpio.patch +++ b/patches/6.19/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From d97bb3ff6090aa36907b602f41fe706968b1c6d4 Mon Sep 17 00:00:00 2001 +From ae46026d2f1deb9c16392a1e473573a9bce5a491 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 9fa321a95eb3..8914a922be2b 100644 +index d6138b2b633a..67094184c150 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -32,7 +32,7 @@ index 9fa321a95eb3..8914a922be2b 100644 #include -@@ -1171,6 +1172,17 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1175,6 +1176,17 @@ static void __init mp_config_acpi_legacy_irqs(void) } } @@ -50,7 +50,7 @@ index 9fa321a95eb3..8914a922be2b 100644 /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -@@ -1227,6 +1239,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) +@@ -1231,6 +1243,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, acpi_gbl_FADT.sci_interrupt); @@ -65,7 +65,7 @@ index 9fa321a95eb3..8914a922be2b 100644 -- 2.53.0 -From 3dba74f758f1ba60e5ccc3bf62fc20b116716555 Mon Sep 17 00:00:00 2001 +From c355da6414efc1bc73199354458c2c94bbfaa339 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,10 +80,10 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 8914a922be2b..c43d0a553867 100644 +index 67094184c150..9c1d2883e13e 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -1174,12 +1174,19 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1178,12 +1178,19 @@ static void __init mp_config_acpi_legacy_irqs(void) static const struct dmi_system_id surface_quirk[] __initconst = { { diff --git a/patches/6.19/0015-rtc.patch b/patches/6.19/0015-rtc.patch index 7d699c3a46..4269a11731 100644 --- a/patches/6.19/0015-rtc.patch +++ b/patches/6.19/0015-rtc.patch @@ -1,4 +1,4 @@ -From 637e1e0d2226b877d44666f60dbe1998ad509c03 Mon Sep 17 00:00:00 2001 +From d83fd5071faf9b027c897daf5f7af4c8daae3557 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.19/0016-hid-surface.patch b/patches/6.19/0016-hid-surface.patch index 4fcf1d3899..7214f9c664 100644 --- a/patches/6.19/0016-hid-surface.patch +++ b/patches/6.19/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 8de1717f5eafe891c12671c2a2bc35424658b45c Mon Sep 17 00:00:00 2001 +From a6ca31c7c9ac7eb4c38caa0dd81dfeb5e25807fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -27,10 +27,10 @@ Patchset: hid-surface create mode 100644 drivers/hid/hid-surface.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 59d597b4effd..d59290a9388e 100644 +index fb65f49b5f65..d31b751a8983 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig -@@ -1142,6 +1142,14 @@ config HID_SUNPLUS +@@ -1143,6 +1143,14 @@ config HID_SUNPLUS help Support for Sunplus wireless desktop. @@ -156,7 +156,7 @@ index 000000000000..a171ea65672f -- 2.53.0 -From de9b50c2e866713da82ecd3856216a7c3ff5dce4 Mon Sep 17 00:00:00 2001 +From de06987ad1db548e02e4a8c255ac45831f0b9bf2 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 @@ -168,26 +168,26 @@ Patchset: hid-surface 1 file changed, 30 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index bd2554f2127f..973f55f23ddf 100644 +index 0c964cc3f9ce..a3507fa03dfe 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(24) - #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(25) -+#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(26) +@@ -83,6 +83,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_YOGABOOK9I BIT(24) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) + #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) ++#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(27) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -244,6 +245,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_SMART_TECH 0x0113 +@@ -246,6 +247,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_APPLE_TOUCHBAR 0x0114 - #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0115 -+#define MT_CLS_SURFACE_TOUCHPAD 0x0116 + #define MT_CLS_YOGABOOK9I 0x0115 + #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0116 ++#define MT_CLS_SURFACE_TOUCHPAD 0x0117 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -452,6 +454,10 @@ static const struct mt_class mt_classes[] = { +@@ -462,6 +464,10 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_WIN8_PTP_BUTTONS, .export_all_inputs = true }, @@ -198,7 +198,7 @@ index bd2554f2127f..973f55f23ddf 100644 { } }; -@@ -2191,11 +2197,30 @@ static void mt_remove(struct hid_device *hdev) +@@ -2257,11 +2263,30 @@ static void mt_remove(struct hid_device *hdev) static void mt_on_hid_hw_open(struct hid_device *hdev) { @@ -229,7 +229,7 @@ index bd2554f2127f..973f55f23ddf 100644 mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); } -@@ -2632,6 +2657,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2707,6 +2732,11 @@ static const struct hid_device_id mt_devices[] = { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_MICROSOFT, 0x09c0) }, diff --git a/patches/6.19/0017-powercap.patch b/patches/6.19/0017-powercap.patch deleted file mode 100644 index 4c8a188334..0000000000 --- a/patches/6.19/0017-powercap.patch +++ /dev/null @@ -1,30 +0,0 @@ -From ce7514b67d4a0481bbc29536ce468c679679dbe6 Mon Sep 17 00:00:00 2001 -From: Daniel Tang -Date: Wed, 14 Jan 2026 20:31:38 -0500 -Subject: [PATCH] powercap: intel_rapl: Add PL4 support for Ice Lake - -Microsoft Surface Pro 7 firmware throttles the processor upon -boot/resume. Userspace needs to be able to restore the correct value. - -Link: https://github.com/linux-surface/linux-surface/issues/706 -Signed-off-by: Daniel Tang -Patchset: powercap ---- - drivers/powercap/intel_rapl_msr.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c -index 9a7e150b3536..a2bc0a9c1e10 100644 ---- a/drivers/powercap/intel_rapl_msr.c -+++ b/drivers/powercap/intel_rapl_msr.c -@@ -162,6 +162,7 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra) - - /* List of verified CPUs. */ - static const struct x86_cpu_id pl4_support_ids[] = { -+ X86_MATCH_VFM(INTEL_ICELAKE_L, NULL), - X86_MATCH_VFM(INTEL_TIGERLAKE_L, NULL), - X86_MATCH_VFM(INTEL_ALDERLAKE, NULL), - X86_MATCH_VFM(INTEL_ALDERLAKE_L, NULL), --- -2.53.0 - From 7ab2b633f266b950255f78e2a7b5e49ed6df609b Mon Sep 17 00:00:00 2001 From: Cornell Chin Date: Thu, 12 Mar 2026 14:56:27 -0400 Subject: [PATCH 211/236] Update v6.19 patches Changes: - Rebase onto v6.19.7 --- patches/6.19/0001-secureboot.patch | 4 +- patches/6.19/0002-surface3.patch | 4 +- patches/6.19/0003-mwifiex.patch | 6 +- patches/6.19/0004-ath10k.patch | 2 +- patches/6.19/0005-ipts.patch | 6 +- patches/6.19/0006-ithc.patch | 4 +- patches/6.19/0007-surface-sam.patch | 4 +- patches/6.19/0008-surface-sam-over-hid.patch | 4 +- patches/6.19/0009-surface-button.patch | 4 +- patches/6.19/0010-surface-typecover.patch | 78 ++++++++++---------- patches/6.19/0011-surface-shutdown.patch | 4 +- patches/6.19/0012-surface-gpe.patch | 2 +- patches/6.19/0013-cameras.patch | 20 ++--- patches/6.19/0014-amd-gpio.patch | 4 +- patches/6.19/0015-rtc.patch | 2 +- patches/6.19/0016-hid-surface.patch | 41 +++++----- 16 files changed, 94 insertions(+), 95 deletions(-) diff --git a/patches/6.19/0001-secureboot.patch b/patches/6.19/0001-secureboot.patch index fced69f3a9..55a2335926 100644 --- a/patches/6.19/0001-secureboot.patch +++ b/patches/6.19/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 5e70f3948db99688eec0b82295617fb08f66e9fc Mon Sep 17 00:00:00 2001 +From 1d9a8c66c2e1c68d77752dc7bd783f687c519cc1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 -- 2.53.0 -From 26de633ca6c52842f679f381897ed4f69b5c1aa6 Mon Sep 17 00:00:00 2001 +From 7d68d0528b1baefe1ebf0ff318f09061cf1427b1 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.19/0002-surface3.patch b/patches/6.19/0002-surface3.patch index f5d71995c3..969249b2de 100644 --- a/patches/6.19/0002-surface3.patch +++ b/patches/6.19/0002-surface3.patch @@ -1,4 +1,4 @@ -From 9f9b1fbb2f62082827262f5aa1a1ce6e40624639 Mon Sep 17 00:00:00 2001 +From e9709bc87f61d85fb6eed62ba88a266fb6518da3 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.53.0 -From dc1bcef8cef69cf7eceaa07ffd74dc957fcfb335 Mon Sep 17 00:00:00 2001 +From 42ddd2ba5cd0463a3d2df2272a62f191d22ce627 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.19/0003-mwifiex.patch b/patches/6.19/0003-mwifiex.patch index 57940221d4..2b28495536 100644 --- a/patches/6.19/0003-mwifiex.patch +++ b/patches/6.19/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 04f816e7f96dc829e15c324812ef93d7af9b08ee Mon Sep 17 00:00:00 2001 +From 7b0c30b3efdeab4fe238004dd7c011793329bbfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.53.0 -From b406ec8c7d68bbc4c571672324247c8cd37de533 Mon Sep 17 00:00:00 2001 +From c6d66a3d653f7d45e4cc8dff959511679ac201df Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.53.0 -From 6d158290073b93a10b5f62ad0db9e764d5f04ff6 Mon Sep 17 00:00:00 2001 +From 2cf7e582ded09f5482d3721b5a81de9aa1b2027f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.19/0004-ath10k.patch b/patches/6.19/0004-ath10k.patch index bd668aeb77..d6b954158f 100644 --- a/patches/6.19/0004-ath10k.patch +++ b/patches/6.19/0004-ath10k.patch @@ -1,4 +1,4 @@ -From e99f630d657295b9f6d12c6f61a3d208f392e757 Mon Sep 17 00:00:00 2001 +From 7f09f88ee1771f6325d8db56e8a69391a4fd64ff Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.19/0005-ipts.patch b/patches/6.19/0005-ipts.patch index 4e50a30032..d7296cece3 100644 --- a/patches/6.19/0005-ipts.patch +++ b/patches/6.19/0005-ipts.patch @@ -1,4 +1,4 @@ -From 129296e814686b07a5e6fbdd0411498a90f37e94 Mon Sep 17 00:00:00 2001 +From 4e1ed5bb13aa2ebae2796efb4341f4b0ed816857 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e569558b9..c19dfba542c1 100644 -- 2.53.0 -From 9fe94d5f42f186a8110033722d26ce29d40d3685 Mon Sep 17 00:00:00 2001 +From 6010fdefe06779084aac28317e06a3d4243a97c2 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index 705828b06e32..1400bf283aa6 100644 -- 2.53.0 -From a08b1047b9f0a392b8089c5d47c49c9acd309072 Mon Sep 17 00:00:00 2001 +From fa46f8f24352c39eb8f0478a672e980866a2153c Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.19/0006-ithc.patch b/patches/6.19/0006-ithc.patch index 99f850144b..aa3a25e7a7 100644 --- a/patches/6.19/0006-ithc.patch +++ b/patches/6.19/0006-ithc.patch @@ -1,4 +1,4 @@ -From 48f246ea9cad43b412653cc9b01386bd68f1a333 Mon Sep 17 00:00:00 2001 +From ffea9ba1573c3aae021d906f01e82c22582c2381 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9c72..c78806d35f2b 100644 -- 2.53.0 -From aad08f7adf72af99b6af60f582c60e40a4d9db16 Mon Sep 17 00:00:00 2001 +From 375553b546124bab124a5961a5770769bd03768e Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.19/0007-surface-sam.patch b/patches/6.19/0007-surface-sam.patch index 77aedd3fa2..39aa39e31d 100644 --- a/patches/6.19/0007-surface-sam.patch +++ b/patches/6.19/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 00d5742cf4d64274b9497b950ebc6af16d80f22f Mon Sep 17 00:00:00 2001 +From 65be11bf7138e9763f1ff24f29dcb5822df59e14 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.53.0 -From 3342129fcc0003ea918230936cf78ba1263e2802 Mon Sep 17 00:00:00 2001 +From 929013d9dccc4f7cff672ddaf1f34098b6f0255d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.19/0008-surface-sam-over-hid.patch b/patches/6.19/0008-surface-sam-over-hid.patch index 1bef3f5d34..4a2d3a03aa 100644 --- a/patches/6.19/0008-surface-sam-over-hid.patch +++ b/patches/6.19/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 0e63337c09db38b0e44f0a7e841e212538cb52c1 Mon Sep 17 00:00:00 2001 +From 3f4b3f98e021ab287bae56357b0917dca828fa2d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a27b7..070c36637811 100644 -- 2.53.0 -From 2dd5dbd39c0ddf1e6c10e50dc481fb753d7a4978 Mon Sep 17 00:00:00 2001 +From 131e0653aab6e56ffcf80b36c50e1fd75cb40494 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.19/0009-surface-button.patch b/patches/6.19/0009-surface-button.patch index 75fbc12e02..1051cd06de 100644 --- a/patches/6.19/0009-surface-button.patch +++ b/patches/6.19/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 7702d0b1c74cce7ffc8f9079f84e94bbca54802c Mon Sep 17 00:00:00 2001 +From 96692406409a5b917db93e581723fcdf73cac0f7 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.53.0 -From fd36767467cd0a6d82445835f8dbd94bc6205668 Mon Sep 17 00:00:00 2001 +From 3cc082107dd60a39a5a29b28a7b3ca89ca11a9b8 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.19/0010-surface-typecover.patch b/patches/6.19/0010-surface-typecover.patch index 6120463709..29d3245752 100644 --- a/patches/6.19/0010-surface-typecover.patch +++ b/patches/6.19/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From fc36351b8c297d2662f956222bd18764bb527b14 Mon Sep 17 00:00:00 2001 +From 75e393ae8d6abde7b5045fc0aa7bb64f8b82bd7c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c4d85089d19b..3d0d35c72189 100644 -- 2.53.0 -From a20b815aee102a70b2a64eba357dffd431c294c4 Mon Sep 17 00:00:00 2001 +From 322aed58d3266eb1250ed2087d69d5f4a030b251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 7daa8f6d8187..2a5c497a519b 100644 +index b8a748bbf0fd..c47a492a14d9 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -97,15 +97,15 @@ index 7daa8f6d8187..2a5c497a519b 100644 #include "hid-haptic.h" -@@ -77,6 +81,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) +@@ -78,6 +82,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) #define MT_QUIRK_YOGABOOK9I BIT(24) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) + #define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(26) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -84,6 +89,8 @@ MODULE_LICENSE("GPL"); +@@ -85,6 +90,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_CLICKPAD 0 #define MT_BUTTONTYPE_PRESSUREPAD 1 @@ -114,7 +114,7 @@ index 7daa8f6d8187..2a5c497a519b 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -187,6 +194,8 @@ struct mt_device { +@@ -188,6 +195,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -123,17 +123,17 @@ index 7daa8f6d8187..2a5c497a519b 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -233,6 +242,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_SMART_TECH 0x0113 +@@ -236,6 +245,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_APPLE_TOUCHBAR 0x0114 #define MT_CLS_YOGABOOK9I 0x0115 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0116 + #define MT_CLS_EGALAX_P80H84 0x0116 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0117 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -438,6 +448,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_YOGABOOK9I, - .export_all_inputs = true +@@ -455,6 +465,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_CONTACT_CNT_ACCURATE, }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, + .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -148,7 +148,7 @@ index 7daa8f6d8187..2a5c497a519b 100644 { } }; -@@ -1919,6 +1939,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1938,6 +1958,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -218,7 +218,7 @@ index 7daa8f6d8187..2a5c497a519b 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1947,6 +2030,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1966,6 +2049,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -228,7 +228,7 @@ index 7daa8f6d8187..2a5c497a519b 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1985,8 +2071,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -2004,8 +2090,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -240,7 +240,7 @@ index 7daa8f6d8187..2a5c497a519b 100644 if (mtclass->name == MT_CLS_APPLE_TOUCHBAR && !hid_find_field(hdev, HID_INPUT_REPORT, -@@ -2000,8 +2088,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -2019,8 +2107,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -252,7 +252,7 @@ index 7daa8f6d8187..2a5c497a519b 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -2062,6 +2152,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -2081,6 +2171,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -260,7 +260,7 @@ index 7daa8f6d8187..2a5c497a519b 100644 timer_delete_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2515,6 +2606,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2548,6 +2639,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, @@ -275,7 +275,7 @@ index 7daa8f6d8187..2a5c497a519b 100644 -- 2.53.0 -From 9c220c6897df451dae5f6463bd98470f26e7eff9 Mon Sep 17 00:00:00 2001 +From 80124dcf4678086cc271bf8b357dc09ca48f7242 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -304,18 +304,18 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 2a5c497a519b..0c964cc3f9ce 100644 +index c47a492a14d9..c92ab7949fa3 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) +@@ -83,6 +83,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_YOGABOOK9I BIT(24) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) + #define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(26) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(27) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -90,6 +91,8 @@ MODULE_LICENSE("GPL"); +@@ -91,6 +92,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_PRESSUREPAD 1 #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 @@ -324,7 +324,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -450,6 +453,7 @@ static const struct mt_class mt_classes[] = { +@@ -467,6 +470,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -332,7 +332,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1484,6 +1488,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1502,6 +1506,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -342,7 +342,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1511,6 +1518,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1529,6 +1536,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -364,7 +364,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1537,6 +1559,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1555,6 +1577,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -372,7 +372,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1544,6 +1567,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1562,6 +1585,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -392,7 +392,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 /* let hid-core decide for the others */ return 0; } -@@ -1553,11 +1589,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1571,11 +1607,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -414,7 +414,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 return 0; } -@@ -1772,6 +1818,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1790,6 +1836,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -457,7 +457,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1829,6 +1911,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1848,6 +1930,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -471,7 +471,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 default: suffix = "UNKNOWN"; break; -@@ -1939,30 +2028,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1958,30 +2047,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -502,7 +502,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1971,8 +2036,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1990,8 +2055,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -514,7 +514,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -2130,13 +2196,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -2149,13 +2215,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -539,7 +539,7 @@ index 2a5c497a519b..0c964cc3f9ce 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -2145,12 +2222,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -2164,12 +2241,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); diff --git a/patches/6.19/0011-surface-shutdown.patch b/patches/6.19/0011-surface-shutdown.patch index 9236832208..19ef9f4567 100644 --- a/patches/6.19/0011-surface-shutdown.patch +++ b/patches/6.19/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 9c5dd3345ee05bc2b993585eb66304455a1c53c9 Mon Sep 17 00:00:00 2001 +From 2c24b35d0d787f2a18d7ab888dbbed6ddac2e665 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index e958ff744335..2053f33968fb 100644 -- 2.53.0 -From 196cad19ffd57eed5b267b9c20904f6208388ad4 Mon Sep 17 00:00:00 2001 +From 11604d71068da35f1affba826a5e747a04dc59b2 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.19/0012-surface-gpe.patch b/patches/6.19/0012-surface-gpe.patch index d80ed78ce1..5c371b8061 100644 --- a/patches/6.19/0012-surface-gpe.patch +++ b/patches/6.19/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From ba43d1d68595eb90cb1a89f303b3ae0d8881c11f Mon Sep 17 00:00:00 2001 +From 7c5dee44b07761097c3b316dfab43c3b3a7d33c3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.19/0013-cameras.patch b/patches/6.19/0013-cameras.patch index 8bb28489b1..e5901f4307 100644 --- a/patches/6.19/0013-cameras.patch +++ b/patches/6.19/0013-cameras.patch @@ -1,4 +1,4 @@ -From ddef27e2262b0aaa2f2e8db5cfd4a26c9fa9767a Mon Sep 17 00:00:00 2001 +From 4ac7306937928935ae4536bcd007703d3a692066 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index b78f6be2f946..801171e2a7ff 100644 -- 2.53.0 -From 9b15e761340a32b556cae410271d474ed218f564 Mon Sep 17 00:00:00 2001 +From aad039b00a2263c4e994e993dd3289d769f0047e Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 1400bf283aa6..cca97e5b276e 100644 -- 2.53.0 -From ff1872c350f3d93ddbc363c92f81b8318303f4e1 Mon Sep 17 00:00:00 2001 +From 29a7e9791f7935cfe381ed87be20ded5ecda0a6f Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.53.0 -From 63b926d5dafab47d37c4341379146e47680a8619 Mon Sep 17 00:00:00 2001 +From 79631ef7ae3eea4ae1eca7deeb0c3da1725792ba Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0175..28b192c9a5ec 100644 -- 2.53.0 -From 78f2aa76c040b63d91ced0c508ce3f5e824fc7b7 Mon Sep 17 00:00:00 2001 +From b2eb9a84356f8f0049d916dd6c2f04d22b3de3c9 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.53.0 -From 68a76f4000077219ade692d9e02e0bb976ecf476 Mon Sep 17 00:00:00 2001 +From 988b06873d87e352a9598460a756205d59c01baf Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.53.0 -From d7c13ebfd24661e4255535aa5f9ea2e519e0d385 Mon Sep 17 00:00:00 2001 +From 1b1a8613b4838ba8759232a38094560f4cd644e3 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.53.0 -From 7214f4920999126ae37ab2bfbd27a92fcbcf5504 Mon Sep 17 00:00:00 2001 +From e7d37e5c84e06ff54f43d5b820a41a3f3b13257d Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.53.0 -From eb238bac83b853ab4ea7cbf68632bf0e52d54dea Mon Sep 17 00:00:00 2001 +From 7a118c2a7ec834d6f24309c7953f89657d8148fa Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 59558335989e..b89765521af5 100644 -- 2.53.0 -From 535249a26f36e154d83a194593ded787f3c50f40 Mon Sep 17 00:00:00 2001 +From 696f95d21cda6339448c5666523737b7b944330f Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 diff --git a/patches/6.19/0014-amd-gpio.patch b/patches/6.19/0014-amd-gpio.patch index e1b22744f5..e5e31c348b 100644 --- a/patches/6.19/0014-amd-gpio.patch +++ b/patches/6.19/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From ae46026d2f1deb9c16392a1e473573a9bce5a491 Mon Sep 17 00:00:00 2001 +From 4398295bbe56b7058be0286e55e70d665e3d9260 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index d6138b2b633a..67094184c150 100644 -- 2.53.0 -From c355da6414efc1bc73199354458c2c94bbfaa339 Mon Sep 17 00:00:00 2001 +From e5f4ba4b2451da3b95c307a2016e0dc68c3726e2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.19/0015-rtc.patch b/patches/6.19/0015-rtc.patch index 4269a11731..929c9ffe3e 100644 --- a/patches/6.19/0015-rtc.patch +++ b/patches/6.19/0015-rtc.patch @@ -1,4 +1,4 @@ -From d83fd5071faf9b027c897daf5f7af4c8daae3557 Mon Sep 17 00:00:00 2001 +From 6df6bf3f82a420b8df4880222d58ad31af615719 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.19/0016-hid-surface.patch b/patches/6.19/0016-hid-surface.patch index 7214f9c664..b5c6106358 100644 --- a/patches/6.19/0016-hid-surface.patch +++ b/patches/6.19/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From a6ca31c7c9ac7eb4c38caa0dd81dfeb5e25807fa Mon Sep 17 00:00:00 2001 +From 466e0c9b2d3ee4869847458ad52f26af730312dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000000..a171ea65672f -- 2.53.0 -From de06987ad1db548e02e4a8c255ac45831f0b9bf2 Mon Sep 17 00:00:00 2001 +From 85f41f30c83b9f25073114d8502293c2a2111ace Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 24 Dec 2025 00:54:44 -0800 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 @@ -164,30 +164,30 @@ Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 Patchset: hid-surface --- - drivers/hid/hid-multitouch.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) + drivers/hid/hid-multitouch.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 0c964cc3f9ce..a3507fa03dfe 100644 +index c92ab7949fa3..a614e543dca9 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -83,6 +83,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_YOGABOOK9I BIT(24) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) - #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) -+#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(27) +@@ -84,6 +84,7 @@ MODULE_LICENSE("GPL"); + #define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(26) + #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(27) ++#define MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE BIT(28) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -246,6 +247,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_APPLE_TOUCHBAR 0x0114 +@@ -249,6 +250,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_YOGABOOK9I 0x0115 - #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0116 -+#define MT_CLS_SURFACE_TOUCHPAD 0x0117 + #define MT_CLS_EGALAX_P80H84 0x0116 + #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0117 ++#define MT_CLS_SURFACE_TOUCHPAD 0x0118 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -462,6 +464,10 @@ static const struct mt_class mt_classes[] = { +@@ -479,6 +481,10 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_WIN8_PTP_BUTTONS, .export_all_inputs = true }, @@ -198,7 +198,7 @@ index 0c964cc3f9ce..a3507fa03dfe 100644 { } }; -@@ -2257,11 +2263,30 @@ static void mt_remove(struct hid_device *hdev) +@@ -2276,12 +2282,29 @@ static void mt_remove(struct hid_device *hdev) static void mt_on_hid_hw_open(struct hid_device *hdev) { @@ -222,14 +222,13 @@ index 0c964cc3f9ce..a3507fa03dfe 100644 + * open/close hooks. Avoid mode switching on hw_open/hw_close for + * those devices. + */ -+ struct mt_device *td = hid_get_drvdata(hdev); + struct mt_device *td = hid_get_drvdata(hdev); + if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) + return; -+ - mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); - } -@@ -2707,6 +2732,11 @@ static const struct hid_device_id mt_devices[] = { + if (td->mtclass.quirks & MT_QUIRK_KEEP_LATENCY_ON_CLOSE) + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE); +@@ -2740,6 +2763,11 @@ static const struct hid_device_id mt_devices[] = { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_MICROSOFT, 0x09c0) }, From dfa17b2d149f39e3977969d5374e7bf27feefab5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 13 Mar 2026 11:39:36 +0100 Subject: [PATCH 212/236] autoupdate: Add v6.19 to maintained versions --- .github/data/autoupdate/maintained-branches.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/data/autoupdate/maintained-branches.conf b/.github/data/autoupdate/maintained-branches.conf index 7435574f39..e64ce76914 100644 --- a/.github/data/autoupdate/maintained-branches.conf +++ b/.github/data/autoupdate/maintained-branches.conf @@ -5,6 +5,7 @@ # The workflow will automatically trigger rebases when new stable tags # matching the version are found (e.g., v6.18.5 for version 6.18) +v6.19-surface:6.19 v6.18-surface:6.18 v6.17-surface:6.17 v6.12-surface:6.12 From a9e299d7ebc99d27a7dfa310ebf249b5d78c64c4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 13 Mar 2026 11:39:55 +0100 Subject: [PATCH 213/236] Add config for v6.19 --- configs/surface-6.19.config | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 configs/surface-6.19.config diff --git a/configs/surface-6.19.config b/configs/surface-6.19.config new file mode 100644 index 0000000000..016efc4198 --- /dev/null +++ b/configs/surface-6.19.config @@ -0,0 +1,86 @@ +## +## Surface Aggregator Module +## +CONFIG_SURFACE_AGGREGATOR=m +# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set +CONFIG_SURFACE_AGGREGATOR_BUS=y +CONFIG_SURFACE_AGGREGATOR_CDEV=m +CONFIG_SURFACE_AGGREGATOR_HUB=m +CONFIG_SURFACE_AGGREGATOR_REGISTRY=m +CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m + +CONFIG_SURFACE_ACPI_NOTIFY=m +CONFIG_SURFACE_DTX=m +CONFIG_SURFACE_PLATFORM_PROFILE=m + +CONFIG_SURFACE_HID=m +CONFIG_SURFACE_KBD=m + +CONFIG_BATTERY_SURFACE=m +CONFIG_CHARGER_SURFACE=m + +CONFIG_SENSORS_SURFACE_TEMP=m +CONFIG_SENSORS_SURFACE_FAN=m + +CONFIG_RTC_DRV_SURFACE=m + +## +## Surface Hotplug +## +CONFIG_SURFACE_HOTPLUG=m + +## +## IPTS and ITHC touchscreen +## +## This only enables the user interface for IPTS/ITHC data. +## For the touchscreen to work, you need to install iptsd. +## +CONFIG_HID_IPTS=m +CONFIG_HID_ITHC=m +CONFIG_INTEL_THC_HID=m +CONFIG_INTEL_QUICKSPI=m + +## +## Cameras: IPU3 +## +CONFIG_VIDEO_DW9719=m +CONFIG_VIDEO_IPU3_IMGU=m +CONFIG_VIDEO_IPU3_CIO2=m +CONFIG_IPU_BRIDGE=m +CONFIG_INTEL_SKL_INT3472=m +CONFIG_REGULATOR_TPS68470=m +CONFIG_COMMON_CLK_TPS68470=m +CONFIG_LEDS_TPS68470=m + +## +## Cameras: Sensor drivers +## +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV8865=m + +## +## Surface 3: atomisp causes problems (see issue #1095). Disable it for now. +## +# CONFIG_INTEL_ATOMISP is not set + +## +## ALS Sensor for Surface Book 3, Surface Laptop 3, Surface Pro 7 +## +CONFIG_APDS9960=m + +## +## Build-in UFS support (required for some Surface Go devices) +## +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m + +## +## Other Drivers +## +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_GPE=m +CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m +CONFIG_HID_SURFACE=m From 5fd2b60514364a2fa7f9c392bb54379f3b19ef70 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 13 Mar 2026 11:56:26 +0100 Subject: [PATCH 214/236] .github: Update actions --- .github/workflows/arch.yml | 10 +++++----- .github/workflows/debian.yml | 10 +++++----- .github/workflows/fedora-40.yml | 10 +++++----- .github/workflows/fedora-41.yml | 10 +++++----- .github/workflows/fedora-42.yml | 10 +++++----- .github/workflows/fedora-43.yml | 6 +++--- .github/workflows/generate-patches.yml | 2 +- .github/workflows/rebase-kernel.yml | 2 +- .github/workflows/sync-kernel-upstream.yml | 2 +- 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/.github/workflows/arch.yml b/.github/workflows/arch.yml index 87d3e269b8..240021f6f6 100644 --- a/.github/workflows/arch.yml +++ b/.github/workflows/arch.yml @@ -25,7 +25,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Initialize containers run: | @@ -64,7 +64,7 @@ jobs: bash ./.github/scripts/package/arch.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: arch-latest path: pkg/arch/kernel/release @@ -76,7 +76,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: arch-latest path: arch-latest @@ -96,10 +96,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: arch-latest path: arch-latest diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 92e703c94c..9024a86ce7 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -25,7 +25,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Initialize containers run: | @@ -64,7 +64,7 @@ jobs: bash ./.github/scripts/package/debian.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: debian-latest path: pkg/debian/release @@ -76,7 +76,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: debian-latest path: debian-latest @@ -96,10 +96,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: debian-latest path: debian-latest diff --git a/.github/workflows/fedora-40.yml b/.github/workflows/fedora-40.yml index 7026a2f8c3..7fc2aaa079 100644 --- a/.github/workflows/fedora-40.yml +++ b/.github/workflows/fedora-40.yml @@ -26,7 +26,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Initialize containers run: | @@ -65,7 +65,7 @@ jobs: bash ./.github/scripts/package/fedora.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: fedora-${{ env.FEDORA }}-latest path: pkg/fedora/kernel-surface/out/x86_64 @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest @@ -97,10 +97,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest diff --git a/.github/workflows/fedora-41.yml b/.github/workflows/fedora-41.yml index 81232c6b53..744b4a211f 100644 --- a/.github/workflows/fedora-41.yml +++ b/.github/workflows/fedora-41.yml @@ -26,7 +26,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Initialize containers run: | @@ -65,7 +65,7 @@ jobs: bash ./.github/scripts/package/fedora.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: fedora-${{ env.FEDORA }}-latest path: pkg/fedora/kernel-surface/out/x86_64 @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest @@ -97,10 +97,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest diff --git a/.github/workflows/fedora-42.yml b/.github/workflows/fedora-42.yml index 8df6f1ab64..7a856f7088 100644 --- a/.github/workflows/fedora-42.yml +++ b/.github/workflows/fedora-42.yml @@ -26,7 +26,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Initialize containers run: | @@ -65,7 +65,7 @@ jobs: bash ./.github/scripts/package/fedora.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: fedora-${{ env.FEDORA }}-latest path: pkg/fedora/kernel-surface/out/x86_64 @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest @@ -97,10 +97,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest diff --git a/.github/workflows/fedora-43.yml b/.github/workflows/fedora-43.yml index 70061087c5..09e6a49cfe 100644 --- a/.github/workflows/fedora-43.yml +++ b/.github/workflows/fedora-43.yml @@ -26,7 +26,7 @@ jobs: remove-docker-images: true - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Initialize containers run: | @@ -65,7 +65,7 @@ jobs: bash ./.github/scripts/package/fedora.sh sign-packages - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: fedora-${{ env.FEDORA }}-latest path: pkg/fedora/kernel-surface/out/x86_64 @@ -97,7 +97,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download artifacts uses: actions/download-artifact@v4 diff --git a/.github/workflows/generate-patches.yml b/.github/workflows/generate-patches.yml index e648bf7059..9fcd63379b 100644 --- a/.github/workflows/generate-patches.yml +++ b/.github/workflows/generate-patches.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout linux-surface repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: token: ${{ secrets.LINUX_SURFACE_BOT_TOKEN }} fetch-depth: 0 diff --git a/.github/workflows/rebase-kernel.yml b/.github/workflows/rebase-kernel.yml index 8f13b01ee7..cb6446dfdf 100644 --- a/.github/workflows/rebase-kernel.yml +++ b/.github/workflows/rebase-kernel.yml @@ -124,7 +124,7 @@ jobs: - name: Upload kernel config artifact if: steps.build.outputs.build_success == 'true' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: kernel-config-${{ inputs.branch }}-${{ steps.rebase.outputs.target_tag }} path: kernel/.config diff --git a/.github/workflows/sync-kernel-upstream.yml b/.github/workflows/sync-kernel-upstream.yml index 4a5e1ab9fc..3585b0158d 100644 --- a/.github/workflows/sync-kernel-upstream.yml +++ b/.github/workflows/sync-kernel-upstream.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Cache kernel repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: kernel/.git key: kernel-git-${{ github.run_number }} From 2ef2cb0d2152855e5261cf8ef7bff264f4857a91 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Fri, 13 Mar 2026 10:44:24 +0000 Subject: [PATCH 215/236] patches/v6.19: Update to v6.19.7 Generated 16 patches from linux-surface/kernel branch v6.19-surface Base version: v6.19.7 Branch: v6.19-surface Automatically generated patches using git-format-patchsets. --- patches/6.19/0001-secureboot.patch | 10 +- patches/6.19/0002-surface3.patch | 12 +-- patches/6.19/0003-mwifiex.patch | 20 ++-- patches/6.19/0004-ath10k.patch | 4 +- patches/6.19/0005-ipts.patch | 68 +++++++------- patches/6.19/0006-ithc.patch | 42 ++++----- patches/6.19/0007-surface-sam.patch | 12 +-- patches/6.19/0008-surface-sam-over-hid.patch | 12 +-- patches/6.19/0009-surface-button.patch | 8 +- patches/6.19/0010-surface-typecover.patch | 12 +-- patches/6.19/0011-surface-shutdown.patch | 12 +-- patches/6.19/0012-surface-gpe.patch | 4 +- patches/6.19/0013-cameras.patch | 96 ++++++++++++++------ patches/6.19/0014-amd-gpio.patch | 8 +- patches/6.19/0015-rtc.patch | 4 +- patches/6.19/0016-hid-surface.patch | 37 +++++--- 16 files changed, 206 insertions(+), 155 deletions(-) diff --git a/patches/6.19/0001-secureboot.patch b/patches/6.19/0001-secureboot.patch index 55a2335926..f1851595d8 100644 --- a/patches/6.19/0001-secureboot.patch +++ b/patches/6.19/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 1d9a8c66c2e1c68d77752dc7bd783f687c519cc1 Mon Sep 17 00:00:00 2001 +From ccf06142002908fbe2b11ad641962f8dd5e017c9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -17,7 +17,7 @@ Patchset: secureboot 1 file changed, 4 insertions(+) diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S -index 9bea5a1e2c52..25848f886ad6 100644 +index 9bea5a1e2..25848f886 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -111,7 +111,11 @@ extra_header_fields: @@ -35,7 +35,7 @@ index 9bea5a1e2c52..25848f886ad6 100644 -- 2.53.0 -From 7d68d0528b1baefe1ebf0ff318f09061cf1427b1 Mon Sep 17 00:00:00 2001 +From d6c0a81b8008dd94fd92fd920739edc68403631c Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter @@ -53,7 +53,7 @@ Patchset: secureboot 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index aa0031108bc1..ca92d0e45220 100644 +index aa0031108..ca92d0e45 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3500,6 +3500,11 @@ Kernel parameters @@ -69,7 +69,7 @@ index aa0031108bc1..ca92d0e45220 100644 Set the time limit in jiffies for a lock acquisition. Acquisitions exceeding this limit diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index af8d07bafe02..9e151554d5a0 100644 +index af8d07baf..9e151554d 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -38,6 +38,7 @@ diff --git a/patches/6.19/0002-surface3.patch b/patches/6.19/0002-surface3.patch index 969249b2de..ae0b74560f 100644 --- a/patches/6.19/0002-surface3.patch +++ b/patches/6.19/0002-surface3.patch @@ -1,4 +1,4 @@ -From e9709bc87f61d85fb6eed62ba88a266fb6518da3 Mon Sep 17 00:00:00 2001 +From 8fff96d33041ea5de8f8543a8aab109b6969d1fd Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -40,7 +40,7 @@ Patchset: surface3 3 files changed, 24 insertions(+) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index 6c8fb7a4dde4..22797a53f4d8 100644 +index 6c8fb7a4d..22797a53f 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { @@ -58,7 +58,7 @@ index 6c8fb7a4dde4..22797a53f4d8 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index f7701b8d0d3c..0708c2fe8f61 100644 +index f7701b8d0..0708c2fe8 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3793,6 +3793,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -78,7 +78,7 @@ index f7701b8d0d3c..0708c2fe8f61 100644 /* * Match for the GPDwin which unfortunately uses somewhat diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index e4c3492a0c28..0b930c91bccb 100644 +index e4c3492a0..0b930c91b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = { @@ -99,7 +99,7 @@ index e4c3492a0c28..0b930c91bccb 100644 -- 2.53.0 -From 42ddd2ba5cd0463a3d2df2272a62f191d22ce627 Mon Sep 17 00:00:00 2001 +From ab2c0739962b01877263d0b49c7f9625e974c30c Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by @@ -179,7 +179,7 @@ Patchset: surface3 1 file changed, 26 insertions(+) diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c -index 6074b7730e86..6aa3e1d6f160 100644 +index 6074b7730..6aa3e1d6f 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -25,6 +25,12 @@ diff --git a/patches/6.19/0003-mwifiex.patch b/patches/6.19/0003-mwifiex.patch index 2b28495536..f5ed88b4c9 100644 --- a/patches/6.19/0003-mwifiex.patch +++ b/patches/6.19/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 7b0c30b3efdeab4fe238004dd7c011793329bbfe Mon Sep 17 00:00:00 2001 +From d77c72bf8b5d9464ac8129871d5d23eada9a9854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -32,7 +32,7 @@ Patchset: mwifiex 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index a760de191fce..db9b203226a8 100644 +index a760de191..db9b20322 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) @@ -58,7 +58,7 @@ index a760de191fce..db9b203226a8 100644 mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index dd6d21f1dbfd..f46b06f8d643 100644 +index dd6d21f1d..f46b06f8d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -151,7 +151,7 @@ index dd6d21f1dbfd..f46b06f8d643 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index d6ff964aec5b..5d30ae39d65e 100644 +index d6ff964ae..5d30ae39d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -4,6 +4,7 @@ @@ -165,7 +165,7 @@ index d6ff964aec5b..5d30ae39d65e 100644 -- 2.53.0 -From c6d66a3d653f7d45e4cc8dff959511679ac201df Mon Sep 17 00:00:00 2001 +From 97ad2bd7702ef8a4b32732d2e7eb002f5dbdc0f3 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -187,7 +187,7 @@ Patchset: mwifiex 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index db9b203226a8..ffd0c1fe9223 100644 +index db9b20322..ffd0c1fe9 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, @@ -212,7 +212,7 @@ index db9b203226a8..ffd0c1fe9223 100644 } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 +index f46b06f8d..99b024ecb 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { @@ -306,7 +306,7 @@ index f46b06f8d643..99b024ecbade 100644 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -index 5d30ae39d65e..c14eb56eb911 100644 +index 5d30ae39d..c14eb56eb 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -5,6 +5,7 @@ @@ -320,7 +320,7 @@ index 5d30ae39d65e..c14eb56eb911 100644 -- 2.53.0 -From 2cf7e582ded09f5482d3721b5a81de9aa1b2027f Mon Sep 17 00:00:00 2001 +From da5d45c8e49bd2a24b4eae12d169615c924e634b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -356,7 +356,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index a41bb1e2a279..572a9bcd2484 100644 +index a41bb1e2a..572a9bcd2 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; diff --git a/patches/6.19/0004-ath10k.patch b/patches/6.19/0004-ath10k.patch index d6b954158f..ff19191232 100644 --- a/patches/6.19/0004-ath10k.patch +++ b/patches/6.19/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 7f09f88ee1771f6325d8db56e8a69391a4fd64ff Mon Sep 17 00:00:00 2001 +From 2f16e6730d0f5e002ed7358921b58df6fb76deca Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -20,7 +20,7 @@ Patchset: ath10k 1 file changed, 57 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 7c2939cbde5f..eb402a3a8c5f 100644 +index 7c2939cbd..eb402a3a8 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -41,6 +41,9 @@ static bool fw_diag_log; diff --git a/patches/6.19/0005-ipts.patch b/patches/6.19/0005-ipts.patch index d7296cece3..eea29f42c5 100644 --- a/patches/6.19/0005-ipts.patch +++ b/patches/6.19/0005-ipts.patch @@ -1,4 +1,4 @@ -From 4e1ed5bb13aa2ebae2796efb4341f4b0ed816857 Mon Sep 17 00:00:00 2001 +From e593ce25ed2c44a19ca0339a379462af7860c264 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -11,7 +11,7 @@ Patchset: ipts 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index fa30899a5fa2..a1864dcb713d 100644 +index fa30899a5..a1864dcb7 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -23,7 +23,7 @@ index fa30899a5fa2..a1864dcb713d 100644 #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 2a6e569558b9..c19dfba542c1 100644 +index 2a6e56955..c19dfba54 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { @@ -37,7 +37,7 @@ index 2a6e569558b9..c19dfba542c1 100644 -- 2.53.0 -From 6010fdefe06779084aac28317e06a3d4243a97c2 Mon Sep 17 00:00:00 2001 +From ee0f79e5728ac3ea01e82faed48adfa50b493b64 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -61,7 +61,7 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 705828b06e32..1400bf283aa6 100644 +index 705828b06..1400bf283 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -39,6 +39,11 @@ @@ -144,7 +144,7 @@ index 705828b06e32..1400bf283aa6 100644 -- 2.53.0 -From fa46f8f24352c39eb8f0478a672e980866a2153c Mon Sep 17 00:00:00 2001 +From a127de7c6235ed359d2a25850ff100ebcec2fb33 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -211,7 +211,7 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 6ff4a3ad34cb..5d41410ac567 100644 +index 6ff4a3ad3..5d41410ac 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1443,6 +1443,8 @@ source "drivers/hid/surface-hid/Kconfig" @@ -224,7 +224,7 @@ index 6ff4a3ad34cb..5d41410ac567 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 361a7daedeb8..b73a1bbd3a1d 100644 +index 361a7daed..b73a1bbd3 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -176,3 +176,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -235,7 +235,7 @@ index 361a7daedeb8..b73a1bbd3a1d 100644 +obj-$(CONFIG_HID_IPTS) += ipts/ diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 000000000000..297401bd388d +index 000000000..297401bd3 --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -255,7 +255,7 @@ index 000000000000..297401bd388d + module will be called ipts. diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile new file mode 100644 -index 000000000000..883896f68e6a +index 000000000..883896f68 --- /dev/null +++ b/drivers/hid/ipts/Makefile @@ -0,0 +1,16 @@ @@ -277,7 +277,7 @@ index 000000000000..883896f68e6a +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 000000000000..63a4934bbc5f +index 000000000..63a4934bb --- /dev/null +++ b/drivers/hid/ipts/cmd.c @@ -0,0 +1,61 @@ @@ -344,7 +344,7 @@ index 000000000000..63a4934bbc5f +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 000000000000..2b4079075b64 +index 000000000..2b4079075 --- /dev/null +++ b/drivers/hid/ipts/cmd.h @@ -0,0 +1,60 @@ @@ -410,7 +410,7 @@ index 000000000000..2b4079075b64 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 000000000000..ba33259f1f7c +index 000000000..ba33259f1 --- /dev/null +++ b/drivers/hid/ipts/context.h @@ -0,0 +1,52 @@ @@ -468,7 +468,7 @@ index 000000000000..ba33259f1f7c +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 000000000000..5360842d260b +index 000000000..5360842d2 --- /dev/null +++ b/drivers/hid/ipts/control.c @@ -0,0 +1,486 @@ @@ -960,7 +960,7 @@ index 000000000000..5360842d260b +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 000000000000..26629c5144ed +index 000000000..26629c514 --- /dev/null +++ b/drivers/hid/ipts/control.h @@ -0,0 +1,126 @@ @@ -1092,7 +1092,7 @@ index 000000000000..26629c5144ed +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 000000000000..307438c7c80c +index 000000000..307438c7c --- /dev/null +++ b/drivers/hid/ipts/desc.h @@ -0,0 +1,80 @@ @@ -1178,7 +1178,7 @@ index 000000000000..307438c7c80c +#endif /* IPTS_DESC_H */ diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 000000000000..7b9f54388a9f +index 000000000..7b9f54388 --- /dev/null +++ b/drivers/hid/ipts/eds1.c @@ -0,0 +1,104 @@ @@ -1288,7 +1288,7 @@ index 000000000000..7b9f54388a9f +} diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h new file mode 100644 -index 000000000000..eeeb6575e3e8 +index 000000000..eeeb6575e --- /dev/null +++ b/drivers/hid/ipts/eds1.h @@ -0,0 +1,35 @@ @@ -1329,7 +1329,7 @@ index 000000000000..eeeb6575e3e8 + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c new file mode 100644 -index 000000000000..639940794615 +index 000000000..639940794 --- /dev/null +++ b/drivers/hid/ipts/eds2.c @@ -0,0 +1,145 @@ @@ -1480,7 +1480,7 @@ index 000000000000..639940794615 +} diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h new file mode 100644 -index 000000000000..064e3716907a +index 000000000..064e37169 --- /dev/null +++ b/drivers/hid/ipts/eds2.h @@ -0,0 +1,35 @@ @@ -1521,7 +1521,7 @@ index 000000000000..064e3716907a + enum hid_report_type report_type, enum hid_class_request request_type); diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c new file mode 100644 -index 000000000000..e34a1a4f9fa7 +index 000000000..e34a1a4f9 --- /dev/null +++ b/drivers/hid/ipts/hid.c @@ -0,0 +1,225 @@ @@ -1752,7 +1752,7 @@ index 000000000000..e34a1a4f9fa7 +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 000000000000..1ebe77447903 +index 000000000..1ebe77447 --- /dev/null +++ b/drivers/hid/ipts/hid.h @@ -0,0 +1,24 @@ @@ -1782,7 +1782,7 @@ index 000000000000..1ebe77447903 +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 000000000000..fb5b5c13ee3e +index 000000000..fb5b5c13e --- /dev/null +++ b/drivers/hid/ipts/main.c @@ -0,0 +1,126 @@ @@ -1914,7 +1914,7 @@ index 000000000000..fb5b5c13ee3e +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 000000000000..1e0395ceae4a +index 000000000..1e0395cea --- /dev/null +++ b/drivers/hid/ipts/mei.c @@ -0,0 +1,188 @@ @@ -2108,7 +2108,7 @@ index 000000000000..1e0395ceae4a +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 000000000000..973bade6b0fd +index 000000000..973bade6b --- /dev/null +++ b/drivers/hid/ipts/mei.h @@ -0,0 +1,66 @@ @@ -2180,7 +2180,7 @@ index 000000000000..973bade6b0fd +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 000000000000..977724c728c3 +index 000000000..977724c72 --- /dev/null +++ b/drivers/hid/ipts/receiver.c @@ -0,0 +1,251 @@ @@ -2437,7 +2437,7 @@ index 000000000000..977724c728c3 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 000000000000..3de7da62d40c +index 000000000..3de7da62d --- /dev/null +++ b/drivers/hid/ipts/receiver.h @@ -0,0 +1,16 @@ @@ -2459,7 +2459,7 @@ index 000000000000..3de7da62d40c +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 000000000000..cc14653b2a9f +index 000000000..cc14653b2 --- /dev/null +++ b/drivers/hid/ipts/resources.c @@ -0,0 +1,131 @@ @@ -2596,7 +2596,7 @@ index 000000000000..cc14653b2a9f +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 000000000000..2068e13285f0 +index 000000000..2068e1328 --- /dev/null +++ b/drivers/hid/ipts/resources.h @@ -0,0 +1,41 @@ @@ -2643,7 +2643,7 @@ index 000000000000..2068e13285f0 +#endif /* IPTS_RESOURCES_H */ diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h new file mode 100644 -index 000000000000..e8dd98895a7e +index 000000000..e8dd98895 --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -2749,7 +2749,7 @@ index 000000000000..e8dd98895a7e +#endif /* IPTS_SPEC_DATA_H */ diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h new file mode 100644 -index 000000000000..41845f9d9025 +index 000000000..41845f9d9 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h @@ -0,0 +1,290 @@ @@ -3045,7 +3045,7 @@ index 000000000000..41845f9d9025 +#endif /* IPTS_SPEC_DEVICE_H */ diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h new file mode 100644 -index 000000000000..5a58d4a0a610 +index 000000000..5a58d4a0a --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h @@ -0,0 +1,34 @@ @@ -3085,7 +3085,7 @@ index 000000000000..5a58d4a0a610 +#endif /* IPTS_SPEC_HID_H */ diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c new file mode 100644 -index 000000000000..355e92bea26f +index 000000000..355e92bea --- /dev/null +++ b/drivers/hid/ipts/thread.c @@ -0,0 +1,84 @@ @@ -3175,7 +3175,7 @@ index 000000000000..355e92bea26f +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 000000000000..1f966b8b32c4 +index 000000000..1f966b8b3 --- /dev/null +++ b/drivers/hid/ipts/thread.h @@ -0,0 +1,59 @@ diff --git a/patches/6.19/0006-ithc.patch b/patches/6.19/0006-ithc.patch index aa3a25e7a7..6dff60186d 100644 --- a/patches/6.19/0006-ithc.patch +++ b/patches/6.19/0006-ithc.patch @@ -1,4 +1,4 @@ -From ffea9ba1573c3aae021d906f01e82c22582c2381 Mon Sep 17 00:00:00 2001 +From a8d1ff29e7670d6a322e281f55e44e5f05ae5816 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -10,7 +10,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 8bcbfe3d9c72..c78806d35f2b 100644 +index 8bcbfe3d9..c78806d35 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -381,6 +381,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) @@ -39,7 +39,7 @@ index 8bcbfe3d9c72..c78806d35f2b 100644 -- 2.53.0 -From 375553b546124bab124a5961a5770769bd03768e Mon Sep 17 00:00:00 2001 +From 95f497e456d533d3e5b93a19bd74b1087144118f Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -86,7 +86,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 5d41410ac567..fb65f49b5f65 100644 +index 5d41410ac..fb65f49b5 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1445,6 +1445,8 @@ source "drivers/hid/intel-thc-hid/Kconfig" @@ -99,7 +99,7 @@ index 5d41410ac567..fb65f49b5f65 100644 # USB support may be used with HID disabled diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index b73a1bbd3a1d..3190ece25626 100644 +index b73a1bbd3..3190ece25 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -178,3 +178,4 @@ obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ @@ -109,7 +109,7 @@ index b73a1bbd3a1d..3190ece25626 100644 +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 000000000000..4937ba131297 +index 000000000..4937ba131 --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -121,7 +121,7 @@ index 000000000000..4937ba131297 + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 000000000000..ede713023609 +index 000000000..ede713023 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -139,7 +139,7 @@ index 000000000000..ede713023609 + module will be called ithc. diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c new file mode 100644 -index 000000000000..2d8c6afe9966 +index 000000000..2d8c6afe9 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,149 @@ @@ -294,7 +294,7 @@ index 000000000000..2d8c6afe9966 + diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h new file mode 100644 -index 000000000000..38c53d916bdb +index 000000000..38c53d916 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.h @@ -0,0 +1,7 @@ @@ -307,7 +307,7 @@ index 000000000000..38c53d916bdb + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 000000000000..bf4eab33062b +index 000000000..bf4eab330 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,312 @@ @@ -625,7 +625,7 @@ index 000000000000..bf4eab33062b + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 000000000000..1749a5819b3e +index 000000000..1749a5819 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,47 @@ @@ -678,7 +678,7 @@ index 000000000000..1749a5819b3e + diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c new file mode 100644 -index 000000000000..065646ab499e +index 000000000..065646ab4 --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.c @@ -0,0 +1,207 @@ @@ -891,7 +891,7 @@ index 000000000000..065646ab499e + diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h new file mode 100644 -index 000000000000..599eb912c8c8 +index 000000000..599eb912c --- /dev/null +++ b/drivers/hid/ithc/ithc-hid.h @@ -0,0 +1,32 @@ @@ -929,7 +929,7 @@ index 000000000000..599eb912c8c8 + diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c new file mode 100644 -index 000000000000..8883987fb352 +index 000000000..8883987fb --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.c @@ -0,0 +1,254 @@ @@ -1189,7 +1189,7 @@ index 000000000000..8883987fb352 + diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h new file mode 100644 -index 000000000000..28d692462072 +index 000000000..28d692462 --- /dev/null +++ b/drivers/hid/ithc/ithc-legacy.h @@ -0,0 +1,8 @@ @@ -1203,7 +1203,7 @@ index 000000000000..28d692462072 + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000000..094d878d671b +index 000000000..094d878d6 --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,438 @@ @@ -1647,7 +1647,7 @@ index 000000000000..094d878d671b + diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c new file mode 100644 -index 000000000000..e2d1690b8cf8 +index 000000000..e2d1690b8 --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.c @@ -0,0 +1,607 @@ @@ -2260,7 +2260,7 @@ index 000000000000..e2d1690b8cf8 + diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h new file mode 100644 -index 000000000000..74d882f6b2f0 +index 000000000..74d882f6b --- /dev/null +++ b/drivers/hid/ithc/ithc-quickspi.h @@ -0,0 +1,39 @@ @@ -2305,7 +2305,7 @@ index 000000000000..74d882f6b2f0 + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 000000000000..c0f13506af20 +index 000000000..c0f13506a --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,154 @@ @@ -2465,7 +2465,7 @@ index 000000000000..c0f13506af20 + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 000000000000..4f541fe533fa +index 000000000..4f541fe53 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,211 @@ @@ -2682,7 +2682,7 @@ index 000000000000..4f541fe533fa + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 000000000000..aec320d4e945 +index 000000000..aec320d4e --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,89 @@ diff --git a/patches/6.19/0007-surface-sam.patch b/patches/6.19/0007-surface-sam.patch index 39aa39e31d..02e4b59f2e 100644 --- a/patches/6.19/0007-surface-sam.patch +++ b/patches/6.19/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 65be11bf7138e9763f1ff24f29dcb5822df59e14 Mon Sep 17 00:00:00 2001 +From 8a3e5e538d441f0238842d3687012146f73fd5a7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -14,7 +14,7 @@ Patchset: surface-sam create mode 100644 drivers/rtc/rtc-surface.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 50ba48609d74..c0afe893e8bf 100644 +index 50ba48609..c0afe893e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1424,6 +1424,13 @@ config RTC_DRV_NTXEC @@ -32,7 +32,7 @@ index 50ba48609d74..c0afe893e8bf 100644 config RTC_DRV_ASM9260 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile -index 6cf7e066314e..18bd33b84d13 100644 +index 6cf7e0663..18bd33b84 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -186,6 +186,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o @@ -45,7 +45,7 @@ index 6cf7e066314e..18bd33b84d13 100644 obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o diff --git a/drivers/rtc/rtc-surface.c b/drivers/rtc/rtc-surface.c new file mode 100644 -index 000000000000..f6c17c4e98d5 +index 000000000..f6c17c4e9 --- /dev/null +++ b/drivers/rtc/rtc-surface.c @@ -0,0 +1,129 @@ @@ -181,7 +181,7 @@ index 000000000000..f6c17c4e98d5 -- 2.53.0 -From 929013d9dccc4f7cff672ddaf1f34098b6f0255d Mon Sep 17 00:00:00 2001 +From bd7ab1df66c8132434dab4256d525018b73bb2a8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 @@ -193,7 +193,7 @@ Patchset: surface-sam 1 file changed, 3 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 78ac3a8fbb73..10fe004e4e21 100644 +index 78ac3a8fb..10fe004e4 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -460,6 +460,9 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { diff --git a/patches/6.19/0008-surface-sam-over-hid.patch b/patches/6.19/0008-surface-sam-over-hid.patch index 4a2d3a03aa..2f4d79b37b 100644 --- a/patches/6.19/0008-surface-sam-over-hid.patch +++ b/patches/6.19/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 3f4b3f98e021ab287bae56357b0917dca828fa2d Mon Sep 17 00:00:00 2001 +From 353e91ef266255484fd6cbe545dd35224455ebc8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -55,7 +55,7 @@ Patchset: surface-sam-over-hid 1 file changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c -index ed90858a27b7..070c36637811 100644 +index ed90858a2..070c36637 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -662,6 +662,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, @@ -109,7 +109,7 @@ index ed90858a27b7..070c36637811 100644 -- 2.53.0 -From 131e0653aab6e56ffcf80b36c50e1fd75cb40494 Mon Sep 17 00:00:00 2001 +From 7034cf5408cc9f36910d562d49544701eada4f6d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -132,7 +132,7 @@ Patchset: surface-sam-over-hid create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig -index f775c6ca1ec1..2075e3852053 100644 +index f775c6ca1..2075e3852 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH @@ -150,7 +150,7 @@ index f775c6ca1ec1..2075e3852053 100644 tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 +index 533443309..7efcd0cdb 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o @@ -163,7 +163,7 @@ index 53344330939b..7efcd0cdb532 100644 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 000000000000..68db237734a1 +index 000000000..68db23773 --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c @@ -0,0 +1,136 @@ diff --git a/patches/6.19/0009-surface-button.patch b/patches/6.19/0009-surface-button.patch index 1051cd06de..7e6cde5459 100644 --- a/patches/6.19/0009-surface-button.patch +++ b/patches/6.19/0009-surface-button.patch @@ -1,4 +1,4 @@ -From 96692406409a5b917db93e581723fcdf73cac0f7 Mon Sep 17 00:00:00 2001 +From f7115f2c8cfd3027b30773702408e5417f3a1281 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -20,7 +20,7 @@ Patchset: surface-button 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index b8cad415c62c..43b5d56383e3 100644 +index b8cad415c..43b5d5638 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644 -- 2.53.0 -From 3cc082107dd60a39a5a29b28a7b3ca89ca11a9b8 Mon Sep 17 00:00:00 2001 +From 9be6a3143aca1fee1dc7e4327abffc1e8999023b Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -96,7 +96,7 @@ Patchset: surface-button 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c -index 2755601f979c..4240c98ca226 100644 +index 2755601f9..4240c98ca 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev) diff --git a/patches/6.19/0010-surface-typecover.patch b/patches/6.19/0010-surface-typecover.patch index 29d3245752..574bc4e35e 100644 --- a/patches/6.19/0010-surface-typecover.patch +++ b/patches/6.19/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 75e393ae8d6abde7b5045fc0aa7bb64f8b82bd7c Mon Sep 17 00:00:00 2001 +From 172f906111072fd1288b89e00702967b021a0a6e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -23,7 +23,7 @@ Patchset: surface-typecover 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index c4d85089d19b..3d0d35c72189 100644 +index c4d85089d..3d0d35c72 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = { @@ -39,7 +39,7 @@ index c4d85089d19b..3d0d35c72189 100644 -- 2.53.0 -From 322aed58d3266eb1250ed2087d69d5f4a030b251 Mon Sep 17 00:00:00 2001 +From 59353f2792d10acfee17bbe9c3fd70ade2794573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index b8a748bbf0fd..c47a492a14d9 100644 +index b8a748bbf..c47a492a1 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -35,7 +35,10 @@ @@ -275,7 +275,7 @@ index b8a748bbf0fd..c47a492a14d9 100644 -- 2.53.0 -From 80124dcf4678086cc271bf8b357dc09ca48f7242 Mon Sep 17 00:00:00 2001 +From 97781bd6764ca03b12b3412671f7e4da18219902 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -304,7 +304,7 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index c47a492a14d9..c92ab7949fa3 100644 +index c47a492a1..c92ab7949 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -83,6 +83,7 @@ MODULE_LICENSE("GPL"); diff --git a/patches/6.19/0011-surface-shutdown.patch b/patches/6.19/0011-surface-shutdown.patch index 19ef9f4567..c2608ad9c9 100644 --- a/patches/6.19/0011-surface-shutdown.patch +++ b/patches/6.19/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 2c24b35d0d787f2a18d7ab888dbbed6ddac2e665 Mon Sep 17 00:00:00 2001 +From 358ac1cebff3b79ce0344d064de1381fb9f1f499 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -23,7 +23,7 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 301a9418e38e..c49bdf52794a 100644 +index 301a9418e..c49bdf527 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) @@ -37,7 +37,7 @@ index 301a9418e38e..c49bdf52794a 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index fd86f72f54ae..14f03bf95644 100644 +index fd86f72f5..14f03bf95 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6377,3 +6377,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) @@ -81,7 +81,7 @@ index fd86f72f54ae..14f03bf95644 100644 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU diff --git a/include/linux/pci.h b/include/linux/pci.h -index e958ff744335..2053f33968fb 100644 +index e958ff744..2053f3396 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -489,6 +489,7 @@ struct pci_dev { @@ -95,7 +95,7 @@ index e958ff744335..2053f33968fb 100644 -- 2.53.0 -From 11604d71068da35f1affba826a5e747a04dc59b2 Mon Sep 17 00:00:00 2001 +From a170a548cda3e202e028a046281efb7615feb0e3 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops @@ -108,7 +108,7 @@ Patchset: surface-shutdown 1 file changed, 13 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index 14f03bf95644..06b2debf32bf 100644 +index 14f03bf95..06b2debf3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6396,6 +6396,13 @@ static const struct dmi_system_id no_shutdown_dmi_table[] = { diff --git a/patches/6.19/0012-surface-gpe.patch b/patches/6.19/0012-surface-gpe.patch index 5c371b8061..a72574f6bb 100644 --- a/patches/6.19/0012-surface-gpe.patch +++ b/patches/6.19/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 7c5dee44b07761097c3b316dfab43c3b3a7d33c3 Mon Sep 17 00:00:00 2001 +From f109080bd768688b8776cde0f1b0126025207317 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -12,7 +12,7 @@ Patchset: surface-gpe 1 file changed, 17 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index b359413903b1..b4496db79f39 100644 +index b35941390..b4496db79 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = { diff --git a/patches/6.19/0013-cameras.patch b/patches/6.19/0013-cameras.patch index e5901f4307..2c91fc4834 100644 --- a/patches/6.19/0013-cameras.patch +++ b/patches/6.19/0013-cameras.patch @@ -1,4 +1,4 @@ -From 4ac7306937928935ae4536bcd007703d3a692066 Mon Sep 17 00:00:00 2001 +From 2a7b899cc1ac6b2a7679324ec07c16d363da19c5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -58,7 +58,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index b78f6be2f946..801171e2a7ff 100644 +index b78f6be2f..801171e2a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2206,6 +2206,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, @@ -74,7 +74,7 @@ index b78f6be2f946..801171e2a7ff 100644 -- 2.53.0 -From aad039b00a2263c4e994e993dd3289d769f0047e Mon Sep 17 00:00:00 2001 +From c8025b53c0c94e169da3811178ba5232a8e60c6f Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -100,7 +100,7 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 1400bf283aa6..cca97e5b276e 100644 +index 1400bf283..cca97e5b2 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -44,6 +44,13 @@ @@ -184,7 +184,7 @@ index 1400bf283aa6..cca97e5b276e 100644 -- 2.53.0 -From 29a7e9791f7935cfe381ed87be20ded5ecda0a6f Mon Sep 17 00:00:00 2001 +From 0931a33bf8faf56c59c2a0f5882319a2ad29d257 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -201,7 +201,7 @@ Patchset: cameras 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 0133405697dc..9e0763bdc758 100644 +index 013340569..9e0763bdc 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) @@ -221,7 +221,7 @@ index 0133405697dc..9e0763bdc758 100644 -- 2.53.0 -From 79631ef7ae3eea4ae1eca7deeb0c3da1725792ba Mon Sep 17 00:00:00 2001 +From 4bdb4c8c928b724a0707f049a79fb95efa643ced Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -236,7 +236,7 @@ Patchset: cameras 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 27afc3fc0175..28b192c9a5ec 100644 +index 27afc3fc0..28b192c9a 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1053,7 +1053,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) @@ -260,7 +260,7 @@ index 27afc3fc0175..28b192c9a5ec 100644 -- 2.53.0 -From b2eb9a84356f8f0049d916dd6c2f04d22b3de3c9 Mon Sep 17 00:00:00 2001 +From 93b58e2c293b772fd0a8f515e84ce2d2461552d1 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -279,7 +279,7 @@ Patchset: cameras 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index 1c08bba9ecb9..57a990d7dc84 100644 +index 1c08bba9e..57a990d7d 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -811,6 +811,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) @@ -294,7 +294,7 @@ index 1c08bba9ecb9..57a990d7dc84 100644 * No reference taken. The reference is held by the device (struct * v4l2_subdev.dev), and async sub-device does not exist independently diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index cb153ce42c45..f11b499e14bb 100644 +index cb153ce42..f11b499e1 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1260,10 +1260,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) @@ -311,7 +311,7 @@ index cb153ce42c45..f11b499e14bb 100644 -- 2.53.0 -From 988b06873d87e352a9598460a756205d59c01baf Mon Sep 17 00:00:00 2001 +From 9a9da6cefd1998e9c75643c378d2306456de27c8 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -327,7 +327,7 @@ Patchset: cameras 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 9e0763bdc758..0976b267972b 100644 +index 9e0763bdc..0976b2679 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -352,7 +352,7 @@ index 9e0763bdc758..0976b267972b 100644 -- 2.53.0 -From 1b1a8613b4838ba8759232a38094560f4cd644e3 Mon Sep 17 00:00:00 2001 +From c6f6ccd18f8bd6acb56a7b5e7494283aa1326bfa Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -370,7 +370,7 @@ Patchset: cameras 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 +index 7807fa329..2d2abb25b 100644 --- a/include/linux/mfd/tps68470.h +++ b/include/linux/mfd/tps68470.h @@ -34,6 +34,7 @@ @@ -393,7 +393,7 @@ index 7807fa329db0..2d2abb25b944 100644 -- 2.53.0 -From e7d37e5c84e06ff54f43d5b820a41a3f3b13257d Mon Sep 17 00:00:00 2001 +From b9a5b7d6ef5df81aacbde1017c071e6414c3dee0 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -416,7 +416,7 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 11e7282dc297..c5665bd5e522 100644 +index 11e7282dc..c5665bd5e 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -998,6 +998,18 @@ config LEDS_TPS6105X @@ -439,7 +439,7 @@ index 11e7282dc297..c5665bd5e522 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 9a0333ec1a86..4e1ca8fc9b41 100644 +index 9a0333ec1..4e1ca8fc9 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o @@ -452,7 +452,7 @@ index 9a0333ec1a86..4e1ca8fc9b41 100644 obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c new file mode 100644 -index 000000000000..35aeb5db89c8 +index 000000000..35aeb5db8 --- /dev/null +++ b/drivers/leds/leds-tps68470.c @@ -0,0 +1,185 @@ @@ -644,7 +644,7 @@ index 000000000000..35aeb5db89c8 -- 2.53.0 -From 7a118c2a7ec834d6f24309c7953f89657d8148fa Mon Sep 17 00:00:00 2001 +From 37def344288ef248b4de0f3288e786ccd7a29dc8 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -660,7 +660,7 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index 59558335989e..b89765521af5 100644 +index 595583359..b89765521 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c @@ -121,6 +121,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) @@ -676,7 +676,7 @@ index 59558335989e..b89765521af5 100644 -- 2.53.0 -From 696f95d21cda6339448c5666523737b7b944330f Mon Sep 17 00:00:00 2001 +From fb12fae1ba3c32222de40a73aded8e832e9999b5 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 @@ -693,7 +693,7 @@ Patchset: cameras 4 files changed, 184 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c -index 162b49046990..85cd0c98af03 100644 +index 162b49046..85cd0c98a 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -2,6 +2,7 @@ @@ -940,7 +940,7 @@ index 162b49046990..85cd0c98af03 100644 }, .probe = ov13858_probe, diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c -index 4cc796bbee92..02236f3db19d 100644 +index 4cc796bbe..02236f3db 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -1396,6 +1396,7 @@ static const struct dev_pm_ops ov5693_pm_ops = { @@ -952,7 +952,7 @@ index 4cc796bbee92..02236f3db19d 100644 }; MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c -index b2b710094914..f5456330bbc9 100644 +index b2b710094..f5456330b 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -61,6 +61,10 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { @@ -967,7 +967,7 @@ index b2b710094914..f5456330bbc9 100644 IPU_SENSOR_CONFIG("INT3474", 1, 180000000), /* Omnivision OV5670 */ diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index 1505fc3ef7a8..20962e8acb26 100644 +index 1505fc3ef..20962e8ac 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -229,6 +229,14 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 @@ -1017,3 +1017,47 @@ index 1505fc3ef7a8..20962e8acb26 100644 -- 2.53.0 +From ccf81864b20f87ab1dcced62301bebfa59da6f1b Mon Sep 17 00:00:00 2001 +From: gabrielstedman +Date: Fri, 13 Mar 2026 08:52:07 +0000 +Subject: [PATCH] media: ipu-bridge: Add front camera rotation quirks for + Surface Pro 8 and 9 + +On the Surface Pro 8 and 9, camera rotation in `ssdb.degree` is `0` (no +rotation) but should be `180`. Add these devices to the respective quirk +list. + +Link: https://github.com/linux-surface/kernel/pull/160 +Patchset: cameras +--- + drivers/media/pci/intel/ipu-bridge.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +index f5456330b..3418ff475 100644 +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -122,6 +122,20 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = { + }, + .driver_data = "OVTI02C1", + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 8"), ++ }, ++ .driver_data = "INT33BE", ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ .driver_data = "OVTI5693", ++ }, + {} /* Terminating entry */ + }; + +-- +2.53.0 + diff --git a/patches/6.19/0014-amd-gpio.patch b/patches/6.19/0014-amd-gpio.patch index e5e31c348b..dcaf7077b0 100644 --- a/patches/6.19/0014-amd-gpio.patch +++ b/patches/6.19/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 4398295bbe56b7058be0286e55e70d665e3d9260 Mon Sep 17 00:00:00 2001 +From e02b4df1bd7305cba15591dab6998eac1b60286d Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index d6138b2b633a..67094184c150 100644 +index d6138b2b6..67094184c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -65,7 +65,7 @@ index d6138b2b633a..67094184c150 100644 -- 2.53.0 -From e5f4ba4b2451da3b95c307a2016e0dc68c3726e2 Mon Sep 17 00:00:00 2001 +From 621498afa39ea7ef34840f681008619c2a186e55 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,7 +80,7 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 67094184c150..9c1d2883e13e 100644 +index 67094184c..9c1d2883e 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1178,12 +1178,19 @@ static void __init mp_config_acpi_legacy_irqs(void) diff --git a/patches/6.19/0015-rtc.patch b/patches/6.19/0015-rtc.patch index 929c9ffe3e..4c9e536f61 100644 --- a/patches/6.19/0015-rtc.patch +++ b/patches/6.19/0015-rtc.patch @@ -1,4 +1,4 @@ -From 6df6bf3f82a420b8df4880222d58ad31af615719 Mon Sep 17 00:00:00 2001 +From e3f4a294a622072d8aa8934774133231950c9adb Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -21,7 +21,7 @@ Patchset: rtc 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index 6d870d97ada6..a19cd08e1554 100644 +index 6d870d97a..a19cd08e1 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -438,6 +438,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, diff --git a/patches/6.19/0016-hid-surface.patch b/patches/6.19/0016-hid-surface.patch index b5c6106358..7e9d4d5be6 100644 --- a/patches/6.19/0016-hid-surface.patch +++ b/patches/6.19/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 466e0c9b2d3ee4869847458ad52f26af730312dd Mon Sep 17 00:00:00 2001 +From e8233c6ddc03fb2271cbb3adab90dc9ff05d1210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -27,7 +27,7 @@ Patchset: hid-surface create mode 100644 drivers/hid/hid-surface.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index fb65f49b5f65..d31b751a8983 100644 +index fb65f49b5..d31b751a8 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1143,6 +1143,14 @@ config HID_SUNPLUS @@ -46,7 +46,7 @@ index fb65f49b5f65..d31b751a8983 100644 tristate "Synaptics RMI4 device support" select RMI4_CORE diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 3190ece25626..4d2891879548 100644 +index 3190ece25..4d2891879 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -174,6 +174,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ @@ -59,7 +59,7 @@ index 3190ece25626..4d2891879548 100644 diff --git a/drivers/hid/hid-surface.c b/drivers/hid/hid-surface.c new file mode 100644 -index 000000000000..a171ea65672f +index 000000000..a171ea656 --- /dev/null +++ b/drivers/hid/hid-surface.c @@ -0,0 +1,90 @@ @@ -156,19 +156,22 @@ index 000000000000..a171ea65672f -- 2.53.0 -From 85f41f30c83b9f25073114d8502293c2a2111ace Mon Sep 17 00:00:00 2001 +From 7d3b3154572eaedfdb72f5a00c3590355ba0ec00 Mon Sep 17 00:00:00 2001 From: LegendaryFire -Date: Wed, 24 Dec 2025 00:54:44 -0800 +Date: Fri, 13 Mar 2026 10:16:37 +0100 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 touch pad +Note: Is this still required with MT_QUIRK_KEEP_LATENCY_ON_CLOSE now +being available? + Patchset: hid-surface --- - drivers/hid/hid-multitouch.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) + drivers/hid/hid-multitouch.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index c92ab7949fa3..a614e543dca9 100644 +index c92ab7949..331e1553d 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -84,6 +84,7 @@ MODULE_LICENSE("GPL"); @@ -198,37 +201,41 @@ index c92ab7949fa3..a614e543dca9 100644 { } }; -@@ -2276,12 +2282,29 @@ static void mt_remove(struct hid_device *hdev) +@@ -2276,6 +2282,17 @@ static void mt_remove(struct hid_device *hdev) static void mt_on_hid_hw_open(struct hid_device *hdev) { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + /* + * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck + * non-functional if we change touchpad reporting modes from the HID + * open/close hooks. Avoid mode switching on hw_open/hw_close for + * those devices. + */ -+ struct mt_device *td = hid_get_drvdata(hdev); + if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) + return; ++ mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); } - static void mt_on_hid_hw_close(struct hid_device *hdev) +@@ -2283,6 +2300,15 @@ static void mt_on_hid_hw_close(struct hid_device *hdev) { + struct mt_device *td = hid_get_drvdata(hdev); + + /* + * Some devices (e.g. Surface Laptop Studio 2 touchpad) can get stuck + * non-functional if we change touchpad reporting modes from the HID + * open/close hooks. Avoid mode switching on hw_open/hw_close for + * those devices. + */ - struct mt_device *td = hid_get_drvdata(hdev); + if (td && td->mtclass.quirks & MT_QUIRK_SKIP_MODESET_ON_HW_OPEN_CLOSE) + return; - ++ if (td->mtclass.quirks & MT_QUIRK_KEEP_LATENCY_ON_CLOSE) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE); -@@ -2740,6 +2763,11 @@ static const struct hid_device_id mt_devices[] = { + else +@@ -2740,6 +2766,11 @@ static const struct hid_device_id mt_devices[] = { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_MICROSOFT, 0x09c0) }, From 17081c102b96328e5eb8686006404706203e7cf4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 13 Mar 2026 11:59:00 +0100 Subject: [PATCH 216/236] fixup! .github: Update actions --- .github/workflows/fedora-43.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/fedora-43.yml b/.github/workflows/fedora-43.yml index 09e6a49cfe..b3fb6dd838 100644 --- a/.github/workflows/fedora-43.yml +++ b/.github/workflows/fedora-43.yml @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest @@ -100,7 +100,7 @@ jobs: uses: actions/checkout@v6 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: fedora-${{ env.FEDORA }}-latest path: fedora-${{ env.FEDORA }}-latest From 177ac06f8ceadbcd44086793520a06164601cfa1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 13 Mar 2026 12:00:02 +0100 Subject: [PATCH 217/236] Update Debian kernel to v6.19.7 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 1a734eb33c..eba00afe5e 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.18.8" +KERNEL_VERSION="6.19.7" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From f5a2c183357da8d5f06c3c37917daa7cb18f22d7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 13 Mar 2026 12:04:37 +0100 Subject: [PATCH 218/236] Update Fedora kernels to v6.19.7 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index ed2f4dcc19..87b681d2fe 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.18.8-0" +PACKAGE_TAG = "kernel-6.19.7-0" ## ## The release number of the modified kernel package. From 6aa67eb4741b5694288b981726f5e3f5227660c4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 13 Mar 2026 12:39:47 +0100 Subject: [PATCH 219/236] pkg/fedora: Update build-system patches --- ...1-Pull-in-iptsd-as-a-weak-dependency.patch | 8 ++-- ...ce-provide-the-standard-package-name.patch | 44 +++++++++---------- ...ce-conflict-with-older-versions-of-t.patch | 28 ++++++------ ...and-service-files-for-keeping-the-su.patch | 22 +++++----- .../0005-Pull-in-intel-vsc-firmware.patch | 8 ++-- .../patches/0006-Drop-riscv64-configs.patch | 12 ++--- .../secureboot/0001-secureboot.patch | 12 ++--- 7 files changed, 67 insertions(+), 67 deletions(-) diff --git a/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch index be10be8f3d..9d31d35f31 100644 --- a/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch +++ b/pkg/fedora/kernel-surface/patches/0001-Pull-in-iptsd-as-a-weak-dependency.patch @@ -1,4 +1,4 @@ -From 5747933cc59471903b75a640b7adc3ee152cb92f Mon Sep 17 00:00:00 2001 +From 00b39641dd3a076142f6ad11021d5a66ee4af942 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:33:03 +0200 Subject: [PATCH 1/6] Pull in iptsd as a weak dependency @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 08ff3553cecc..042a9736e324 100644 +index 0d68a716783e..505f440e04af 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1191,6 +1191,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1255,6 +1255,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index 08ff3553cecc..042a9736e324 100644 Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -- -2.52.0 +2.53.0 diff --git a/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch index d97e8f47fb..dbc4df1bd6 100644 --- a/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch +++ b/pkg/fedora/kernel-surface/patches/0002-Let-kernel-surface-provide-the-standard-package-name.patch @@ -1,4 +1,4 @@ -From 3a68edfb0846e4fea4a947cb70bf3c2eb181ad47 Mon Sep 17 00:00:00 2001 +From 583461fb19d94847a2a2e8b904b57accfdd54ad6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:09:20 +0200 Subject: [PATCH 2/6] Let kernel-surface provide the standard package names @@ -9,18 +9,18 @@ Signed-off-by: Dorian Stoll 1 file changed, 34 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 042a9736e324..23ed1c854ed4 100644 +index 505f440e04af..d92ef1a8d86a 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -747,6 +747,7 @@ Requires: %{name}-modules-uname-r = %{KVERREL} - Requires: %{name}-modules-core-uname-r = %{KVERREL} - Requires: ((%{name}-modules-extra-uname-r = %{KVERREL}) if %{name}-modules-extra-matched) +@@ -784,6 +784,7 @@ Requires: ((%{name}-modules-extra-uname-r = %{KVERREL}) if %{name}-modules-extra + # Prefer the plain kernel-core pkg as core-uname-r provider + Suggests: %{name}-core = %{specversion}-%{release} Provides: installonlypkg(kernel) +Provides: kernel = %{KVERREL} %endif -@@ -1184,7 +1185,9 @@ The %{package_name} meta package +@@ -1248,7 +1249,9 @@ The %{name} meta package Provides: kernel = %{specversion}-%{pkg_release}\ Provides: %{name} = %{specversion}-%{pkg_release}\ %endif\ @@ -30,7 +30,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires(pre): %{kernel_prereq}\ -@@ -1223,6 +1226,7 @@ Summary: Header files for the Linux kernel for use by glibc +@@ -1287,6 +1290,7 @@ Summary: Header files for the Linux kernel for use by glibc Obsoletes: glibc-kernheaders < 3.0-46 Provides: glibc-kernheaders = 3.0-46 %if 0%{?gemini} @@ -38,7 +38,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}-headers = %{specversion}-%{release} Obsoletes: kernel-headers < %{specversion} %endif -@@ -1238,6 +1242,7 @@ glibc package. +@@ -1302,6 +1306,7 @@ glibc package. %package cross-headers Summary: Header files for the Linux kernel for use by cross-glibc %if 0%{?gemini} @@ -46,7 +46,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}-cross-headers = %{specversion}-%{release} Obsoletes: kernel-cross-headers < %{specversion} %endif -@@ -1477,6 +1482,7 @@ Linux kernel, suitable for the kabi-dw tool. +@@ -1582,6 +1587,7 @@ Linux kernel, suitable for the kabi-dw tool. %package %{?1:%{1}-}debuginfo\ Summary: Debug information for package %{name}%{?1:-%{1}}\ Requires: %{name}-debuginfo-common-%{_target_cpu} = %{specrpmversion}-%{release}\ @@ -54,7 +54,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}%{?1:-%{1}}-debuginfo-%{_target_cpu} = %{specrpmversion}-%{release}\ Provides: installonlypkg(kernel)\ AutoReqProv: no\ -@@ -1493,10 +1499,13 @@ This is required to use SystemTap with %{name}%{?1:-%{1}}-%{KVERREL}.\ +@@ -1605,10 +1611,13 @@ This is required to use SystemTap with %{name}%{?1:-%{1}}-%{KVERREL}.\ %define kernel_devel_package(m) \ %package %{?1:%{1}-}devel\ Summary: Development package for building kernel modules to match the %{?2:%{2} }kernel\ @@ -68,15 +68,15 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: installonlypkg(kernel)\ AutoReqProv: no\ Requires(pre): findutils\ -@@ -1526,6 +1535,7 @@ against the %{?2:%{2} }kernel package.\ +@@ -1638,6 +1647,7 @@ against the %{?2:%{2} }kernel package.\ Summary: Meta package to install matching core and devel packages for a given %{?2:%{2} }kernel\ - Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ - Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ + Requires: %{name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ + Requires: %{name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ +Provides: kernel-devel-matched = %{specrpmversion}-%{release}\ %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1545,10 +1555,14 @@ This meta package provides a single reference that other packages can Require to +@@ -1657,10 +1667,14 @@ This meta package provides a single reference that other packages can Require to %package %{?1:%{1}-}modules-internal\ Summary: Extra kernel modules to match the %{?2:%{2} }kernel\ Group: System Environment/Kernel\ @@ -91,7 +91,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}%{?1:-%{1}}-modules-internal-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ -@@ -1566,10 +1580,14 @@ This package provides kernel modules for the %{?2:%{2} }kernel package for Red H +@@ -1684,10 +1698,14 @@ This package provides kernel modules for the %{?2:%{2} }kernel package for Red H %define kernel_modules_extra_package(m) \ %package %{?1:%{1}-}modules-extra\ Summary: Extra kernel modules to match the %{?2:%{2} }kernel\ @@ -106,7 +106,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ -@@ -1590,10 +1608,14 @@ This package provides less commonly used kernel modules for the %{?2:%{2} }kerne +@@ -1714,10 +1732,14 @@ This package provides less commonly used kernel modules for the %{?2:%{2} }kerne %define kernel_modules_package(m) \ %package %{?1:%{1}-}modules\ Summary: kernel modules to match the %{?2:%{2}-}core kernel\ @@ -121,7 +121,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ -@@ -1613,10 +1635,14 @@ This package provides commonly used kernel modules for the %{?2:%{2}-}core kerne +@@ -1737,10 +1759,14 @@ This package provides commonly used kernel modules for the %{?2:%{2}-}core kerne %define kernel_modules_core_package(m) \ %package %{?1:%{1}-}modules-core\ Summary: Core kernel modules to match the %{?2:%{2}-}core kernel\ @@ -136,7 +136,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ %if %{-m:1}%{!-m:0}\ -@@ -1643,6 +1669,7 @@ Requires: ((%{name}-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) +@@ -1769,6 +1795,7 @@ Suggests: %{name}-%{1}-core = %{specversion}-%{release}\ Requires: realtime-setup\ %endif\ Provides: installonlypkg(kernel)\ @@ -144,7 +144,7 @@ index 042a9736e324..23ed1c854ed4 100644 %description %{1}\ The meta-package for the %{1} kernel\ %{nil} -@@ -1659,8 +1686,10 @@ The meta-package for the %{1} kernel\ +@@ -1790,8 +1817,10 @@ The meta-package for the %{1} kernel\ %define kernel_variant_package(n:mo) \ %package %{?1:%{1}-}core\ Summary: %{variant_summary}\ @@ -155,7 +155,7 @@ index 042a9736e324..23ed1c854ed4 100644 %if %{-m:1}%{!-m:0}\ Requires: %{name}-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ -@@ -1685,6 +1714,7 @@ Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant % +@@ -1816,6 +1845,7 @@ Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant % %package %{?1:%{1}-}uki-virt\ Summary: %{variant_summary} unified kernel image for virtual machines\ Provides: installonlypkg(kernel)\ @@ -163,7 +163,7 @@ index 042a9736e324..23ed1c854ed4 100644 Provides: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires(pre): %{kernel_prereq}\ -@@ -1709,10 +1739,14 @@ Requires(pre): systemd >= 254-1\ +@@ -1853,10 +1883,14 @@ Conflicts: %{name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ %package %{?1:%{1}-}modules-partner\ Summary: Extra kernel modules to match the %{?2:%{2} }kernel\ Group: System Environment/Kernel\ @@ -179,5 +179,5 @@ index 042a9736e324..23ed1c854ed4 100644 Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ -- -2.52.0 +2.53.0 diff --git a/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch index 7f5234cd94..ae8b1df794 100644 --- a/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch +++ b/pkg/fedora/kernel-surface/patches/0003-Let-kernel-surface-conflict-with-older-versions-of-t.patch @@ -1,4 +1,4 @@ -From e36d14a3c95845d54befe766b15a89d9ca65e1ef Mon Sep 17 00:00:00 2001 +From 1fed6b82af53c4949cb64a53ba4ecc080a764e25 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:10:38 +0200 Subject: [PATCH 3/6] Let kernel-surface conflict with older versions of the @@ -10,11 +10,11 @@ Signed-off-by: Dorian Stoll 1 file changed, 18 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 23ed1c854ed4..81bb35bb8e36 100644 +index d92ef1a8d86a..c5748edf9301 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -748,6 +748,10 @@ Requires: %{name}-modules-core-uname-r = %{KVERREL} - Requires: ((%{name}-modules-extra-uname-r = %{KVERREL}) if %{name}-modules-extra-matched) +@@ -785,6 +785,10 @@ Requires: ((%{name}-modules-extra-uname-r = %{KVERREL}) if %{name}-modules-extra + Suggests: %{name}-core = %{specversion}-%{release} Provides: installonlypkg(kernel) Provides: kernel = %{KVERREL} + @@ -24,7 +24,7 @@ index 23ed1c854ed4..81bb35bb8e36 100644 %endif -@@ -1507,6 +1511,8 @@ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +@@ -1619,6 +1623,8 @@ Provides: kernel-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}-devel-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: kernel-devel = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ @@ -33,16 +33,16 @@ index 23ed1c854ed4..81bb35bb8e36 100644 AutoReqProv: no\ Requires(pre): findutils\ Requires: findutils\ -@@ -1536,6 +1542,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ - Requires: %{package_name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ - Requires: %{package_name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ +@@ -1648,6 +1654,8 @@ Summary: Meta package to install matching core and devel packages for a given %{ + Requires: %{name}%{?1:-%{1}}-devel = %{specrpmversion}-%{release}\ + Requires: %{name}%{?1:-%{1}}-core = %{specrpmversion}-%{release}\ Provides: kernel-devel-matched = %{specrpmversion}-%{release}\ +Conflicts: %{package_name}-devel-matched < 6.3.7-2\ +Obsoletes: %{package_name}-devel-matched < 6.3.7-2\ %description %{?1:%{1}-}devel-matched\ This meta package is used to install matching core and devel packages for a given %{?2:%{2} }kernel.\ %{nil} -@@ -1592,6 +1600,8 @@ Provides: %{name}%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{ +@@ -1710,6 +1718,8 @@ Provides: %{name}%{?1:-%{1}}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ @@ -51,7 +51,7 @@ index 23ed1c854ed4..81bb35bb8e36 100644 %if %{-m:1}%{!-m:0}\ Requires: %{name}-modules-extra-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1619,6 +1629,8 @@ Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +@@ -1743,6 +1753,8 @@ Provides: kernel%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}%{?1:-%{1}}-modules-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ @@ -60,7 +60,7 @@ index 23ed1c854ed4..81bb35bb8e36 100644 %if %{-m:1}%{!-m:0}\ Requires: %{name}-modules-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1645,6 +1657,8 @@ Provides: installonlypkg(kernel-module)\ +@@ -1769,6 +1781,8 @@ Provides: installonlypkg(kernel-module)\ Provides: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Requires: %{name}-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ @@ -69,7 +69,7 @@ index 23ed1c854ed4..81bb35bb8e36 100644 %if %{-m:1}%{!-m:0}\ Requires: %{name}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ %endif\ -@@ -1668,6 +1682,8 @@ Requires: ((%{name}-%{1}-modules-extra-uname-r = %{KVERREL}%{uname_suffix %{1}}) +@@ -1794,6 +1808,8 @@ Suggests: %{name}-%{1}-core = %{specversion}-%{release}\ %if "%{1}" == "rt" || "%{1}" == "rt-debug" || "%{1}" == "rt-64k" || "%{1}" == "rt-64k-debug"\ Requires: realtime-setup\ %endif\ @@ -78,7 +78,7 @@ index 23ed1c854ed4..81bb35bb8e36 100644 Provides: installonlypkg(kernel)\ Provides: kernel = %{KVERREL}+%{1}\ %description %{1}\ -@@ -1690,6 +1706,8 @@ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ +@@ -1821,6 +1837,8 @@ Provides: kernel-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: %{name}-%{?1:%{1}-}core-uname-r = %{KVERREL}%{uname_suffix %{?1}}\ Provides: installonlypkg(kernel)\ Provides: kernel-%{?1:%{1}-}core = %{KVERREL}%{uname_suffix %{?1}}\ @@ -88,5 +88,5 @@ index 23ed1c854ed4..81bb35bb8e36 100644 Requires: %{name}-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ Requires: %{name}-%{?1:%{1}-}-modules-core-uname-r = %{KVERREL}%{uname_variant %{?1}}\ -- -2.52.0 +2.53.0 diff --git a/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch index f85919bc53..b4d8c8eef9 100644 --- a/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch +++ b/pkg/fedora/kernel-surface/patches/0004-Install-scripts-and-service-files-for-keeping-the-su.patch @@ -1,4 +1,4 @@ -From f7f864a34eb97847097e2250129a8b04dfeb8bff Mon Sep 17 00:00:00 2001 +From 9b58106e19b6de4e9acf3c65f13e5b23083a59f4 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:12:29 +0200 Subject: [PATCH 4/6] Install scripts and service files for keeping the surface @@ -10,10 +10,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 33 insertions(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 81bb35bb8e36..67aaf5883051 100644 +index c5748edf9301..f26b37b3354d 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1161,6 +1161,11 @@ Source4000: README.rst +@@ -1221,6 +1221,11 @@ Source4000: README.rst Source4001: rpminspect.yaml Source4002: gating.yaml @@ -25,7 +25,7 @@ index 81bb35bb8e36..67aaf5883051 100644 ## Patches needed for building this package %if !%{nopatches} -@@ -1199,6 +1204,7 @@ Requires(pre): %{initrd_prereq}\ +@@ -1263,6 +1268,7 @@ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ Recommends: iptsd\ @@ -33,7 +33,7 @@ index 81bb35bb8e36..67aaf5883051 100644 Requires(preun): systemd >= 200\ Conflicts: xfsprogs < 4.3.0-1\ Conflicts: xorg-x11-drv-vmmouse < 13.0.99\ -@@ -1213,6 +1219,13 @@ AutoProv: yes\ +@@ -1277,6 +1283,13 @@ AutoProv: yes\ %{nil} @@ -47,7 +47,7 @@ index 81bb35bb8e36..67aaf5883051 100644 %package doc Summary: Various documentation bits found in the kernel source Group: Documentation -@@ -3475,6 +3488,11 @@ find Documentation -type d | xargs chmod u+w +@@ -3688,6 +3701,11 @@ find Documentation -type d | xargs chmod u+w cd linux-%{KVERREL} @@ -59,7 +59,7 @@ index 81bb35bb8e36..67aaf5883051 100644 # re-define RPM_VMLINUX_H, because it doesn't carry over from %build RPM_VMLINUX_H="$(cat ../vmlinux_h_path)" -@@ -3784,6 +3802,15 @@ popd +@@ -4111,6 +4129,15 @@ popd ### scripts ### @@ -73,9 +73,9 @@ index 81bb35bb8e36..67aaf5883051 100644 +%systemd_postun_with_restart linux-surface-default-watchdog.path + %if %{with_tools} - %post -n %{package_name}-tools-libs + %post -n %{name}-tools-libs /sbin/ldconfig -@@ -4266,6 +4293,12 @@ fi\ +@@ -4657,6 +4684,12 @@ fi\ %{_libexecdir}/kselftests %endif @@ -86,8 +86,8 @@ index 81bb35bb8e36..67aaf5883051 100644 +%{_presetdir}/90-linux-surface-default-watchdog.preset + # empty meta-package - %if %{with_up_base} + %if %{with_stock_base} %ifnarch %nobuildarches noarch -- -2.52.0 +2.53.0 diff --git a/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch index 53c5de73ac..d89dec8195 100644 --- a/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch +++ b/pkg/fedora/kernel-surface/patches/0005-Pull-in-intel-vsc-firmware.patch @@ -1,4 +1,4 @@ -From 86059570fd818aeb68dc7caf725a996e3183d0e1 Mon Sep 17 00:00:00 2001 +From 7b83cf743f7a012affbf7ad47a42f36da014f236 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Tue, 30 Sep 2025 20:14:00 +0200 Subject: [PATCH 5/6] Pull in intel-vsc-firmware @@ -9,10 +9,10 @@ This package contains the IPU3 firmware needed for camera support. 1 file changed, 1 insertion(+) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 67aaf5883051..79e67a8b1440 100644 +index f26b37b3354d..14a3f28bf01f 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1203,6 +1203,7 @@ Requires(pre): %{kernel_prereq}\ +@@ -1267,6 +1267,7 @@ Requires(pre): %{kernel_prereq}\ Requires(pre): %{initrd_prereq}\ Requires(pre): ((linux-firmware >= 20150904-56.git6ebf5d57) if linux-firmware)\ Recommends: linux-firmware\ @@ -21,5 +21,5 @@ index 67aaf5883051..79e67a8b1440 100644 Recommends: %{package_name}-default-watchdog\ Requires(preun): systemd >= 200\ -- -2.52.0 +2.53.0 diff --git a/pkg/fedora/kernel-surface/patches/0006-Drop-riscv64-configs.patch b/pkg/fedora/kernel-surface/patches/0006-Drop-riscv64-configs.patch index 103d7ef4bf..7b6faa1248 100644 --- a/pkg/fedora/kernel-surface/patches/0006-Drop-riscv64-configs.patch +++ b/pkg/fedora/kernel-surface/patches/0006-Drop-riscv64-configs.patch @@ -1,4 +1,4 @@ -From ded050bca1992e57147e86986acbf2a6c46fd91c Mon Sep 17 00:00:00 2001 +From fc4c2e2d568d9de2be9d00c8ae9b343d9e130000 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 30 Dec 2025 23:42:38 +0100 Subject: [PATCH 6/6] Drop riscv64 configs @@ -50,10 +50,10 @@ index 2f739fc47f31..4e56dcad5f76 100644 -riscv64=generic:generic-riscv:generic-riscv-riscv64 -riscv64-debug=generic:generic-riscv:generic-riscv-riscv64:debug:debug-riscv-riscv64 diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index 79e67a8b1440..be4e401212b5 100644 +index 14a3f28bf01f..b3a243782b75 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -1015,9 +1015,6 @@ Source33: %{name}-x86_64-debug-rhel.config +@@ -1074,9 +1074,6 @@ Source33: %{name}-x86_64-debug-rhel.config # ARM64 64K page-size kernel config Source42: %{name}-aarch64-64k-rhel.config Source43: %{name}-aarch64-64k-debug-rhel.config @@ -63,7 +63,7 @@ index 79e67a8b1440..be4e401212b5 100644 %endif %if %{include_rhel} || %{include_automotive} -@@ -1039,8 +1036,6 @@ Source58: %{name}-s390x-fedora.config +@@ -1098,8 +1095,6 @@ Source58: %{name}-s390x-fedora.config Source59: %{name}-s390x-debug-fedora.config Source60: %{name}-x86_64-fedora.config Source61: %{name}-x86_64-debug-fedora.config @@ -72,7 +72,7 @@ index 79e67a8b1440..be4e401212b5 100644 Source62: def_variants.yaml.fedora %endif -@@ -1125,8 +1120,6 @@ Source482: %{name}-aarch64-rt-64k-fedora.config +@@ -1185,8 +1180,6 @@ Source482: %{name}-aarch64-rt-64k-fedora.config Source483: %{name}-aarch64-rt-64k-debug-fedora.config Source484: %{name}-x86_64-rt-fedora.config Source485: %{name}-x86_64-rt-debug-fedora.config @@ -82,5 +82,5 @@ index 79e67a8b1440..be4e401212b5 100644 %endif -- -2.52.0 +2.53.0 diff --git a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch index 2b2cb43403..e5dbc4e158 100644 --- a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch +++ b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch @@ -1,4 +1,4 @@ -From e59f7b88079429cd5c373e4518864a87135d2bf8 Mon Sep 17 00:00:00 2001 +From 16c8e79a86657783a74ea1458d46dfb050534132 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 22 Jul 2023 10:45:33 +0200 Subject: [PATCH] Use a custom key and certificate for Secure Boot signing @@ -9,10 +9,10 @@ Signed-off-by: Dorian Stoll 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template -index ca141beda4fd..bbe58bf955f0 100644 +index 0d68a716783e..0a96b1115a2b 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template -@@ -849,6 +849,7 @@ BuildRequires: system-sb-certs +@@ -910,6 +910,7 @@ BuildRequires: system-sb-certs %ifarch x86_64 aarch64 riscv64 BuildRequires: nss-tools BuildRequires: pesign >= 0.10-4 @@ -20,7 +20,7 @@ index ca141beda4fd..bbe58bf955f0 100644 %endif %endif %endif -@@ -942,6 +943,13 @@ Source13: redhatsecureboot501.cer +@@ -1013,6 +1014,13 @@ Source13: redhatsecureboot501.cer %define signing_key_filename kernel-signing-s390.cer %endif @@ -34,7 +34,7 @@ index ca141beda4fd..bbe58bf955f0 100644 # Fedora/ELN pesign macro expects to see these cert file names, see: # https://github.com/rhboot/pesign/blob/main/src/pesign-rpmbuild-helper.in#L216 %if 0%{?fedora}%{?eln} -@@ -2373,7 +2381,7 @@ BuildKernel() { +@@ -2574,7 +2582,7 @@ BuildKernel() { %ifarch x86_64 aarch64 %{log_msg "Sign kernel image"} @@ -44,5 +44,5 @@ index ca141beda4fd..bbe58bf955f0 100644 %ifarch s390x ppc64le if [ -x /usr/bin/rpm-sign ]; then -- -2.51.0 +2.53.0 From 73e26d02077e2b8abaebe7ca334ada7b40152044 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sat, 14 Mar 2026 09:25:35 +0000 Subject: [PATCH 220/236] patches/v6.19: Update to v6.19.8 Generated 16 patches from linux-surface/kernel branch v6.19-surface Base version: v6.19.8 Branch: v6.19-surface Automatically generated patches using git-format-patchsets. --- patches/6.19/0001-secureboot.patch | 4 ++-- patches/6.19/0002-surface3.patch | 4 ++-- patches/6.19/0003-mwifiex.patch | 6 +++--- patches/6.19/0004-ath10k.patch | 2 +- patches/6.19/0005-ipts.patch | 6 +++--- patches/6.19/0006-ithc.patch | 4 ++-- patches/6.19/0007-surface-sam.patch | 4 ++-- patches/6.19/0008-surface-sam-over-hid.patch | 4 ++-- patches/6.19/0009-surface-button.patch | 4 ++-- patches/6.19/0010-surface-typecover.patch | 6 +++--- patches/6.19/0011-surface-shutdown.patch | 4 ++-- patches/6.19/0012-surface-gpe.patch | 2 +- patches/6.19/0013-cameras.patch | 22 ++++++++++---------- patches/6.19/0014-amd-gpio.patch | 4 ++-- patches/6.19/0015-rtc.patch | 2 +- patches/6.19/0016-hid-surface.patch | 4 ++-- 16 files changed, 41 insertions(+), 41 deletions(-) diff --git a/patches/6.19/0001-secureboot.patch b/patches/6.19/0001-secureboot.patch index f1851595d8..bdfade986b 100644 --- a/patches/6.19/0001-secureboot.patch +++ b/patches/6.19/0001-secureboot.patch @@ -1,4 +1,4 @@ -From ccf06142002908fbe2b11ad641962f8dd5e017c9 Mon Sep 17 00:00:00 2001 +From 7d201613b9e598df5b51b9345a54ecadaac3eb20 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2..25848f886 100644 -- 2.53.0 -From d6c0a81b8008dd94fd92fd920739edc68403631c Mon Sep 17 00:00:00 2001 +From 68d5a2a32c55afab7aed55f9334f35bff9f7b119 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.19/0002-surface3.patch b/patches/6.19/0002-surface3.patch index ae0b74560f..f900d9fd66 100644 --- a/patches/6.19/0002-surface3.patch +++ b/patches/6.19/0002-surface3.patch @@ -1,4 +1,4 @@ -From 8fff96d33041ea5de8f8543a8aab109b6969d1fd Mon Sep 17 00:00:00 2001 +From 768f0e265602d98b3c51a39a5a4259937fb795b4 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0..0b930c91b 100644 -- 2.53.0 -From ab2c0739962b01877263d0b49c7f9625e974c30c Mon Sep 17 00:00:00 2001 +From 092d2600301127e07e9f0a9376e78453578d30ba Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.19/0003-mwifiex.patch b/patches/6.19/0003-mwifiex.patch index f5ed88b4c9..c3e01f8646 100644 --- a/patches/6.19/0003-mwifiex.patch +++ b/patches/6.19/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From d77c72bf8b5d9464ac8129871d5d23eada9a9854 Mon Sep 17 00:00:00 2001 +From 1cb8b0055cccf3a466b21fdbb507cef8425980dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.53.0 -From 97ad2bd7702ef8a4b32732d2e7eb002f5dbdc0f3 Mon Sep 17 00:00:00 2001 +From f5454fb0678f6a0a451cf0da228c9b1b993437c2 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.53.0 -From da5d45c8e49bd2a24b4eae12d169615c924e634b Mon Sep 17 00:00:00 2001 +From 901b2af94faae241a5d8c1b91dd844a4cb6b3ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.19/0004-ath10k.patch b/patches/6.19/0004-ath10k.patch index ff19191232..5fb08595f9 100644 --- a/patches/6.19/0004-ath10k.patch +++ b/patches/6.19/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 2f16e6730d0f5e002ed7358921b58df6fb76deca Mon Sep 17 00:00:00 2001 +From cfd60c7e9860fe0ff2840433934be98f516c03f7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.19/0005-ipts.patch b/patches/6.19/0005-ipts.patch index eea29f42c5..d0e56b6ed6 100644 --- a/patches/6.19/0005-ipts.patch +++ b/patches/6.19/0005-ipts.patch @@ -1,4 +1,4 @@ -From e593ce25ed2c44a19ca0339a379462af7860c264 Mon Sep 17 00:00:00 2001 +From 28e9cf5ef53f9f3e8da04a85d4928a594ffaf502 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e56955..c19dfba54 100644 -- 2.53.0 -From ee0f79e5728ac3ea01e82faed48adfa50b493b64 Mon Sep 17 00:00:00 2001 +From 72740aa77740092fa7f448ac1dd7f2a92af2261a Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index 705828b06..1400bf283 100644 -- 2.53.0 -From a127de7c6235ed359d2a25850ff100ebcec2fb33 Mon Sep 17 00:00:00 2001 +From aa91547471bf61ae51e3b59a8d122d37c6ce8a93 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.19/0006-ithc.patch b/patches/6.19/0006-ithc.patch index 6dff60186d..a142964d82 100644 --- a/patches/6.19/0006-ithc.patch +++ b/patches/6.19/0006-ithc.patch @@ -1,4 +1,4 @@ -From a8d1ff29e7670d6a322e281f55e44e5f05ae5816 Mon Sep 17 00:00:00 2001 +From 55e86797e434d35ad49d5fc5ffbc8c17f4bc1404 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9..c78806d35 100644 -- 2.53.0 -From 95f497e456d533d3e5b93a19bd74b1087144118f Mon Sep 17 00:00:00 2001 +From 1cf2103b5e8668521b74da4136e06ee5a17144f3 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.19/0007-surface-sam.patch b/patches/6.19/0007-surface-sam.patch index 02e4b59f2e..566e13d4f5 100644 --- a/patches/6.19/0007-surface-sam.patch +++ b/patches/6.19/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 8a3e5e538d441f0238842d3687012146f73fd5a7 Mon Sep 17 00:00:00 2001 +From ecae0cc0c11be8bf32d363f0c7f3e6d3242bdc9f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000..f6c17c4e9 -- 2.53.0 -From bd7ab1df66c8132434dab4256d525018b73bb2a8 Mon Sep 17 00:00:00 2001 +From 3d1173c2c4513aa4da28ac1f3fd883671769ca02 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.19/0008-surface-sam-over-hid.patch b/patches/6.19/0008-surface-sam-over-hid.patch index 2f4d79b37b..c92dfcd707 100644 --- a/patches/6.19/0008-surface-sam-over-hid.patch +++ b/patches/6.19/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 353e91ef266255484fd6cbe545dd35224455ebc8 Mon Sep 17 00:00:00 2001 +From 3ea6bdb7f77252d22d062947f8aa00f383864777 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a2..070c36637 100644 -- 2.53.0 -From 7034cf5408cc9f36910d562d49544701eada4f6d Mon Sep 17 00:00:00 2001 +From 2b9da1194a4f203a0707700a59393e6920393c34 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.19/0009-surface-button.patch b/patches/6.19/0009-surface-button.patch index 7e6cde5459..149688f0de 100644 --- a/patches/6.19/0009-surface-button.patch +++ b/patches/6.19/0009-surface-button.patch @@ -1,4 +1,4 @@ -From f7115f2c8cfd3027b30773702408e5417f3a1281 Mon Sep 17 00:00:00 2001 +From da7cd214e4a45c233a6be4a97449030592d005e1 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c..43b5d5638 100644 -- 2.53.0 -From 9be6a3143aca1fee1dc7e4327abffc1e8999023b Mon Sep 17 00:00:00 2001 +From 3ec94f2758eaae1d2d7e84e2205ff5ad2c582ae1 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.19/0010-surface-typecover.patch b/patches/6.19/0010-surface-typecover.patch index 574bc4e35e..0b231595b5 100644 --- a/patches/6.19/0010-surface-typecover.patch +++ b/patches/6.19/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 172f906111072fd1288b89e00702967b021a0a6e Mon Sep 17 00:00:00 2001 +From ff5baefb34222c3fdeac0852a4a7501bc659e486 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c4d85089d..3d0d35c72 100644 -- 2.53.0 -From 59353f2792d10acfee17bbe9c3fd70ade2794573 Mon Sep 17 00:00:00 2001 +From 09af9d07fa295c8f3b7768a74fd7737a7cbaddcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -275,7 +275,7 @@ index b8a748bbf..c47a492a1 100644 -- 2.53.0 -From 97781bd6764ca03b12b3412671f7e4da18219902 Mon Sep 17 00:00:00 2001 +From 0344ec52910f491718ad1c2457a11be29096be8f Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.19/0011-surface-shutdown.patch b/patches/6.19/0011-surface-shutdown.patch index c2608ad9c9..5888b7d191 100644 --- a/patches/6.19/0011-surface-shutdown.patch +++ b/patches/6.19/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 358ac1cebff3b79ce0344d064de1381fb9f1f499 Mon Sep 17 00:00:00 2001 +From dd2208ea4f12d8eafde91b5fd6861db06cb7710e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index e958ff744..2053f3396 100644 -- 2.53.0 -From a170a548cda3e202e028a046281efb7615feb0e3 Mon Sep 17 00:00:00 2001 +From 4951c289333bfc16f42fac59a5d02afbdd1979c9 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.19/0012-surface-gpe.patch b/patches/6.19/0012-surface-gpe.patch index a72574f6bb..12ba186b3c 100644 --- a/patches/6.19/0012-surface-gpe.patch +++ b/patches/6.19/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From f109080bd768688b8776cde0f1b0126025207317 Mon Sep 17 00:00:00 2001 +From 958fc5f748b02cf51b294f693215d1c1d40fd66e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.19/0013-cameras.patch b/patches/6.19/0013-cameras.patch index 2c91fc4834..8b0676e5b9 100644 --- a/patches/6.19/0013-cameras.patch +++ b/patches/6.19/0013-cameras.patch @@ -1,4 +1,4 @@ -From 2a7b899cc1ac6b2a7679324ec07c16d363da19c5 Mon Sep 17 00:00:00 2001 +From c1c1eb1b2d1d034dfe351ea51efd25ef502db25e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index b78f6be2f..801171e2a 100644 -- 2.53.0 -From c8025b53c0c94e169da3811178ba5232a8e60c6f Mon Sep 17 00:00:00 2001 +From 4b553e59c7d3ff31429e4dd08a0460b11bab94dd Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index 1400bf283..cca97e5b2 100644 -- 2.53.0 -From 0931a33bf8faf56c59c2a0f5882319a2ad29d257 Mon Sep 17 00:00:00 2001 +From e161e5012e6858f2715f72668ea2fc0d7aeb89da Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 013340569..9e0763bdc 100644 -- 2.53.0 -From 4bdb4c8c928b724a0707f049a79fb95efa643ced Mon Sep 17 00:00:00 2001 +From 9c649457de8b93596baaa80f4f8c00e3d9baba20 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0..28b192c9a 100644 -- 2.53.0 -From 93b58e2c293b772fd0a8f515e84ce2d2461552d1 Mon Sep 17 00:00:00 2001 +From a83903189bc92cdd72dd802072f2518bbad79ee3 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42..f11b499e1 100644 -- 2.53.0 -From 9a9da6cefd1998e9c75643c378d2306456de27c8 Mon Sep 17 00:00:00 2001 +From bd907090c2084997d86042ba1961a066e5f6cce8 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc..0976b2679 100644 -- 2.53.0 -From c6f6ccd18f8bd6acb56a7b5e7494283aa1326bfa Mon Sep 17 00:00:00 2001 +From b4551d25d8d3b88500baa0b2d0cd3e5b60438daf Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.53.0 -From b9a5b7d6ef5df81aacbde1017c071e6414c3dee0 Mon Sep 17 00:00:00 2001 +From 3a215fa6681957570a03d2fa2a936c4400a0248c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000..35aeb5db8 -- 2.53.0 -From 37def344288ef248b4de0f3288e786ccd7a29dc8 Mon Sep 17 00:00:00 2001 +From b581a619711c71600e9f083e3f8d3a36092cb11f Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 595583359..b89765521 100644 -- 2.53.0 -From fb12fae1ba3c32222de40a73aded8e832e9999b5 Mon Sep 17 00:00:00 2001 +From b1dc230fffb35a88809f6c7877416887c1fb3d20 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 @@ -1017,7 +1017,7 @@ index 1505fc3ef..20962e8ac 100644 -- 2.53.0 -From ccf81864b20f87ab1dcced62301bebfa59da6f1b Mon Sep 17 00:00:00 2001 +From f51a44f59234d641cd068c4c1ba7c643dfe4c0ef Mon Sep 17 00:00:00 2001 From: gabrielstedman Date: Fri, 13 Mar 2026 08:52:07 +0000 Subject: [PATCH] media: ipu-bridge: Add front camera rotation quirks for diff --git a/patches/6.19/0014-amd-gpio.patch b/patches/6.19/0014-amd-gpio.patch index dcaf7077b0..a6bd8004af 100644 --- a/patches/6.19/0014-amd-gpio.patch +++ b/patches/6.19/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From e02b4df1bd7305cba15591dab6998eac1b60286d Mon Sep 17 00:00:00 2001 +From 2ffa10c995b5823878f9b56f4d5eceb3a87d9cb4 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index d6138b2b6..67094184c 100644 -- 2.53.0 -From 621498afa39ea7ef34840f681008619c2a186e55 Mon Sep 17 00:00:00 2001 +From 3b8b8afd11fb27fc4d120a260e0c0cbdf3d86b01 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.19/0015-rtc.patch b/patches/6.19/0015-rtc.patch index 4c9e536f61..465c21ee5e 100644 --- a/patches/6.19/0015-rtc.patch +++ b/patches/6.19/0015-rtc.patch @@ -1,4 +1,4 @@ -From e3f4a294a622072d8aa8934774133231950c9adb Mon Sep 17 00:00:00 2001 +From 5eabba9ccc2f5ffa4017887d669b7c0d4f05e793 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.19/0016-hid-surface.patch b/patches/6.19/0016-hid-surface.patch index 7e9d4d5be6..e1373ba54a 100644 --- a/patches/6.19/0016-hid-surface.patch +++ b/patches/6.19/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From e8233c6ddc03fb2271cbb3adab90dc9ff05d1210 Mon Sep 17 00:00:00 2001 +From ceceaa9e24416cdb4fa910ff6a2edcd83ec19d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000..a171ea656 -- 2.53.0 -From 7d3b3154572eaedfdb72f5a00c3590355ba0ec00 Mon Sep 17 00:00:00 2001 +From 57d61aff0b53b089227f5a794363fec829114fc5 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Fri, 13 Mar 2026 10:16:37 +0100 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 From a519f516de9f0c2c711a30dce4ed7d0975a6965f Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sat, 14 Mar 2026 09:21:51 +0000 Subject: [PATCH 221/236] patches/v6.18: Update to v6.18.18 Generated 16 patches from linux-surface/kernel branch v6.18-surface Base version: v6.18.18 Branch: v6.18-surface Automatically generated patches using git-format-patchsets. --- patches/6.18/0001-secureboot.patch | 4 ++-- patches/6.18/0002-surface3.patch | 4 ++-- patches/6.18/0003-mwifiex.patch | 6 +++--- patches/6.18/0004-ath10k.patch | 2 +- patches/6.18/0005-ipts.patch | 6 +++--- patches/6.18/0006-ithc.patch | 4 ++-- patches/6.18/0007-surface-sam.patch | 4 ++-- patches/6.18/0008-surface-sam-over-hid.patch | 4 ++-- patches/6.18/0009-surface-button.patch | 4 ++-- patches/6.18/0010-surface-typecover.patch | 6 +++--- patches/6.18/0011-surface-shutdown.patch | 4 ++-- patches/6.18/0012-surface-gpe.patch | 2 +- patches/6.18/0013-cameras.patch | 22 ++++++++++---------- patches/6.18/0014-amd-gpio.patch | 4 ++-- patches/6.18/0015-rtc.patch | 2 +- patches/6.18/0016-hid-surface.patch | 4 ++-- 16 files changed, 41 insertions(+), 41 deletions(-) diff --git a/patches/6.18/0001-secureboot.patch b/patches/6.18/0001-secureboot.patch index 9eb4a97f79..fa7267b88e 100644 --- a/patches/6.18/0001-secureboot.patch +++ b/patches/6.18/0001-secureboot.patch @@ -1,4 +1,4 @@ -From eba5e12b81b4d83ed0e11ecc6a6943f72d80a877 Mon Sep 17 00:00:00 2001 +From b342b1a9a445ba8b8aa73b945f25740e3cd8da58 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index 9bea5a1e2..25848f886 100644 -- 2.53.0 -From 619c5d07ffbbb58b4db1889d92810b617d80efca Mon Sep 17 00:00:00 2001 +From b106412124df576bc860bb2fdf1e1d3678a3fe75 Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.18/0002-surface3.patch b/patches/6.18/0002-surface3.patch index ff51f4d26b..cf175f0d38 100644 --- a/patches/6.18/0002-surface3.patch +++ b/patches/6.18/0002-surface3.patch @@ -1,4 +1,4 @@ -From 160f6904e9ad7e4a85ef37528386df468ed4a61b Mon Sep 17 00:00:00 2001 +From 0a7aed31749d66652fd63b5843fa6b97febdb2d1 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -99,7 +99,7 @@ index e4c3492a0..0b930c91b 100644 -- 2.53.0 -From 74659866d3a11f0effe87b52b20a8120a50d02fe Mon Sep 17 00:00:00 2001 +From 4dcd8430344c4c7d852ffc32e3ad29ee7313e371 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH] surface3-spi: workaround: disable DMA mode to avoid crash by diff --git a/patches/6.18/0003-mwifiex.patch b/patches/6.18/0003-mwifiex.patch index c8667287bd..e551094736 100644 --- a/patches/6.18/0003-mwifiex.patch +++ b/patches/6.18/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 6fef82bcc4edac718ab9f73f653be5bac8251009 Mon Sep 17 00:00:00 2001 +From 126a8c1d504d8377d222b88bc2d19313eacf8244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.53.0 -From a15f448edf557b3d022f0474d5b67b08399e0746 Mon Sep 17 00:00:00 2001 +From 80cb290812b649955d874929dd84559fbdaaa9d6 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.53.0 -From 89de4725f7b15a3a27fbe851993c472889a304bb Mon Sep 17 00:00:00 2001 +From c5d8dc3870658c58d7fff6ee6a58163f8335dd9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.18/0004-ath10k.patch b/patches/6.18/0004-ath10k.patch index 60320fbe6b..562d4787fc 100644 --- a/patches/6.18/0004-ath10k.patch +++ b/patches/6.18/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 3bcff82851b221fb8bddd3e085806afe4d32eb89 Mon Sep 17 00:00:00 2001 +From 69078fd9804149d199b3fa8e713b80760a11b596 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.18/0005-ipts.patch b/patches/6.18/0005-ipts.patch index 8ff8498853..4b2d28f778 100644 --- a/patches/6.18/0005-ipts.patch +++ b/patches/6.18/0005-ipts.patch @@ -1,4 +1,4 @@ -From 08a7818553d5e5f08c49233b7c26c1caa7010e5e Mon Sep 17 00:00:00 2001 +From d87fa52961781a386b63b57e26ca965f20a20f9a Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 2a6e56955..c19dfba54 100644 -- 2.53.0 -From fbe131b36a06da8329f88913aa49b9979525e1d5 Mon Sep 17 00:00:00 2001 +From 9c1a6cafefa706cc777274302be1956509067f7c Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index 49e83c856..a3e35c77d 100644 -- 2.53.0 -From 94d61f62aff23b9d8f14383a9bf5372999c2431c Mon Sep 17 00:00:00 2001 +From 4e909ce1db9f221bec5f6761da1c74868e646567 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.18/0006-ithc.patch b/patches/6.18/0006-ithc.patch index 812cba5f23..e3a9357c06 100644 --- a/patches/6.18/0006-ithc.patch +++ b/patches/6.18/0006-ithc.patch @@ -1,4 +1,4 @@ -From d27f63695839ae3cc725c8d7666405dc0f7bb109 Mon Sep 17 00:00:00 2001 +From 7889794c87f8ead7509001798da50606553010d4 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 8bcbfe3d9..c78806d35 100644 -- 2.53.0 -From 6a4e9c31e39e92ca1fea20632d41df7d67f666f3 Mon Sep 17 00:00:00 2001 +From 0a194a407857f526d06d1e459b81faa5be2e4275 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.18/0007-surface-sam.patch b/patches/6.18/0007-surface-sam.patch index 049a351679..812d33a772 100644 --- a/patches/6.18/0007-surface-sam.patch +++ b/patches/6.18/0007-surface-sam.patch @@ -1,4 +1,4 @@ -From 3ba7fa6e5236b7ea4141f9f85d8636066d81dc0a Mon Sep 17 00:00:00 2001 +From d0c0e2cf7bca1d124ec51f129d2ae259d0291cb5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 17 Jun 2022 02:14:00 +0200 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator @@ -181,7 +181,7 @@ index 000000000..f6c17c4e9 -- 2.53.0 -From 58c3cb2fbdedd7c57ddb040217355ff718975fa5 Mon Sep 17 00:00:00 2001 +From da4d9417542e3a5ba645dc5c069c8709344c6d7d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Surface Laptop 7 diff --git a/patches/6.18/0008-surface-sam-over-hid.patch b/patches/6.18/0008-surface-sam-over-hid.patch index 1845d26b53..2dd060151a 100644 --- a/patches/6.18/0008-surface-sam-over-hid.patch +++ b/patches/6.18/0008-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From bffb18859041b06d2a02156b19f987103916d86b Mon Sep 17 00:00:00 2001 +From a7cb180b16908683b3716d74a61c98c7f5fc1b46 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index ed90858a2..070c36637 100644 -- 2.53.0 -From 0a73b819912d300caccd86b2a5d6aee5eb161f3e Mon Sep 17 00:00:00 2001 +From 6b54c1290d843259d1c732221e863ae35d648a2d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.18/0009-surface-button.patch b/patches/6.18/0009-surface-button.patch index 6559dda9cd..0cc44f8b6b 100644 --- a/patches/6.18/0009-surface-button.patch +++ b/patches/6.18/0009-surface-button.patch @@ -1,4 +1,4 @@ -From a7f4f1bfba7c8d96baadf1212006957c533f0d8a Mon Sep 17 00:00:00 2001 +From 298e817335b8804e0b889f25237d4282917a46b0 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index b8cad415c..43b5d5638 100644 -- 2.53.0 -From b4ca6508297bbaf5ec174aae5abbb0f7ca46f611 Mon Sep 17 00:00:00 2001 +From 55c5ef0db3fd3ec8ef996ab1cf229f5b6a01c659 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.18/0010-surface-typecover.patch b/patches/6.18/0010-surface-typecover.patch index 5da817cd9d..c8265ce867 100644 --- a/patches/6.18/0010-surface-typecover.patch +++ b/patches/6.18/0010-surface-typecover.patch @@ -1,4 +1,4 @@ -From 3016f423ab0e10093a4ab502ca73830eb6760ea7 Mon Sep 17 00:00:00 2001 +From 65586462f66578997979fffce0d14c364e97bd24 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index c4d85089d..3d0d35c72 100644 -- 2.53.0 -From 36fe9a8a785b46e63aadc92ff71ffa99d24069ac Mon Sep 17 00:00:00 2001 +From 66f68837779ede11cda8e29afc46ce0f43cfa081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -274,7 +274,7 @@ index af19e089b..ab040ea64 100644 -- 2.53.0 -From 40bf0ca78f732f1041154d32180ddcb44571cad2 Mon Sep 17 00:00:00 2001 +From 6612b8a0b4db1e57a95fad53ebfe68ba90bc8faf Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet diff --git a/patches/6.18/0011-surface-shutdown.patch b/patches/6.18/0011-surface-shutdown.patch index 9e756f2745..c3e95f9b35 100644 --- a/patches/6.18/0011-surface-shutdown.patch +++ b/patches/6.18/0011-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 5e53f226080bd78c28c436c087c7ba7743add4f7 Mon Sep 17 00:00:00 2001 +From f4dbafd07e1b1f9f5c1656646443c6e58528a62d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown method @@ -95,7 +95,7 @@ index 05aeee8c8..006ea71ce 100644 -- 2.53.0 -From 12f8026700b5bc2d333b6da7528c31c82f379edb Mon Sep 17 00:00:00 2001 +From fd4fa0b63f720afbebfd215e5337ecf847eb3c9c Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Wed, 7 Jan 2026 01:06:25 +0100 Subject: [PATCH] PCI: Add Surface Laptop Studio 2 devices to shutdown ops diff --git a/patches/6.18/0012-surface-gpe.patch b/patches/6.18/0012-surface-gpe.patch index 2d982bead9..822b8a09e4 100644 --- a/patches/6.18/0012-surface-gpe.patch +++ b/patches/6.18/0012-surface-gpe.patch @@ -1,4 +1,4 @@ -From 766818fce3dbaefe80ab8c7b09bf83114d5d5d3e Mon Sep 17 00:00:00 2001 +From 6a418143256e871795b4ddb618e151e1186e341c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.18/0013-cameras.patch b/patches/6.18/0013-cameras.patch index 1d0e529e91..0cccba8a31 100644 --- a/patches/6.18/0013-cameras.patch +++ b/patches/6.18/0013-cameras.patch @@ -1,4 +1,4 @@ -From d693daba3c12c84c53d38ab8e21e04963035734a Mon Sep 17 00:00:00 2001 +From 6d89ae89f9a4b6613019c0964c1c59e823755abf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ef16d58b2..a6bad2679 100644 -- 2.53.0 -From c6ba60b1e0f18c27516419a7c611fbf7885e773c Mon Sep 17 00:00:00 2001 +From c6b57220a5b99a279d2eb4197f290c9ff2127a9e Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index a3e35c77d..28567ba59 100644 -- 2.53.0 -From 86a9e06fbb44086759a3b055638c00d4a489b21d Mon Sep 17 00:00:00 2001 +From adfe6d571518a91dc024839f490d68dc83892814 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 013340569..9e0763bdc 100644 -- 2.53.0 -From 45343ef53c4105b306b313789527661a81c52d04 Mon Sep 17 00:00:00 2001 +From 2a5f75ce5abfd79f192bcabecfaaddb494a126ef Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -260,7 +260,7 @@ index 27afc3fc0..28b192c9a 100644 -- 2.53.0 -From 32cea2dfe991c162cc0392db93ecee4d88a0ce76 Mon Sep 17 00:00:00 2001 +From 91a6592078b6ac05615ebb6de7936f24723e6364 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -311,7 +311,7 @@ index cb153ce42..f11b499e1 100644 -- 2.53.0 -From 3ea45d9e1f9663a9b89962d6f99e9ed85e0fdbf9 Mon Sep 17 00:00:00 2001 +From 71d9f6f5a29533047a4ba72646f1a6c3bf2ccfc5 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -352,7 +352,7 @@ index 9e0763bdc..0976b2679 100644 -- 2.53.0 -From 533c08f4994d9e3af95aaf417149646f2a12123c Mon Sep 17 00:00:00 2001 +From 3b5333d4354852e552f2250b2cefa33a3d307e0d Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -393,7 +393,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.53.0 -From 86d68e16a7aee5b4f0568b842a5b2b8a7907b916 Mon Sep 17 00:00:00 2001 +From 14bab8cfe711721bedae032517272f5c1eda237c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -644,7 +644,7 @@ index 000000000..35aeb5db8 -- 2.53.0 -From 38402757f9881b3afd7b1b33c9c0a66f9a80379f Mon Sep 17 00:00:00 2001 +From 8385a094f55efa199beac99879304d048a9ed696 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -676,7 +676,7 @@ index 032fbcb98..e03a1d8cd 100644 -- 2.53.0 -From 652839ecc85fc2856d0a6c52498d61c04851c41f Mon Sep 17 00:00:00 2001 +From 6caa822dedfe4d4a164070424caae770db458798 Mon Sep 17 00:00:00 2001 From: Tooraj Taraz Date: Wed, 31 Dec 2025 00:35:50 +0100 Subject: [PATCH] Add camera support for Surface Pro 9 @@ -1017,7 +1017,7 @@ index 1505fc3ef..20962e8ac 100644 -- 2.53.0 -From 70b17884899e2d0abd5503efd9aff0ea05473233 Mon Sep 17 00:00:00 2001 +From b8440f1dcf2ce055afd00c733546fa209c74c09d Mon Sep 17 00:00:00 2001 From: gabrielstedman Date: Fri, 13 Mar 2026 08:52:07 +0000 Subject: [PATCH] media: ipu-bridge: Add front camera rotation quirks for diff --git a/patches/6.18/0014-amd-gpio.patch b/patches/6.18/0014-amd-gpio.patch index 4dbb0b5200..da29e996fc 100644 --- a/patches/6.18/0014-amd-gpio.patch +++ b/patches/6.18/0014-amd-gpio.patch @@ -1,4 +1,4 @@ -From 8ff4b5a2af058663e766fc8edf8f24f8c21b007a Mon Sep 17 00:00:00 2001 +From a6c275f92edf5ac7d5528a240a961d3697e0e900 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -65,7 +65,7 @@ index d6138b2b6..67094184c 100644 -- 2.53.0 -From 0fb8ce91b92a1f4e90a29abb12ef276c3a1c9528 Mon Sep 17 00:00:00 2001 +From 9b1d1ebf89898d157aed1cc245368a992fbef83e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override diff --git a/patches/6.18/0015-rtc.patch b/patches/6.18/0015-rtc.patch index f2dc0ff2c6..431f77614d 100644 --- a/patches/6.18/0015-rtc.patch +++ b/patches/6.18/0015-rtc.patch @@ -1,4 +1,4 @@ -From 4658081050d245b515333e5639b118e3fa6168dd Mon Sep 17 00:00:00 2001 +From 6103981ac27c5d9ff98baada8ed6befeafab2242 Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms diff --git a/patches/6.18/0016-hid-surface.patch b/patches/6.18/0016-hid-surface.patch index 6e005ebf4c..b4be4c8f4c 100644 --- a/patches/6.18/0016-hid-surface.patch +++ b/patches/6.18/0016-hid-surface.patch @@ -1,4 +1,4 @@ -From 8e9bab94eaad38d01e2df96a6a3888cfb727f488 Mon Sep 17 00:00:00 2001 +From 9f5befc32ec4d2f7124a03afd88b0b3070b822c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Coffey?= Date: Fri, 10 Oct 2025 19:04:03 +0100 Subject: [PATCH] HID: Add hid-surface driver to filter BTN_0 (FN key) @@ -156,7 +156,7 @@ index 000000000..a171ea656 -- 2.53.0 -From 79ae9d899ddc4ac988403fe349166dfd0dadc081 Mon Sep 17 00:00:00 2001 +From 0c2e6a571542e179a7461d38efd2ce8d590a3f35 Mon Sep 17 00:00:00 2001 From: LegendaryFire Date: Fri, 13 Mar 2026 10:16:37 +0100 Subject: [PATCH] hid/multitouch: Prevent mode set on Surface Laptop Studio 2 From 89717a8f2a51d0d9f3a39b1cc1aa38ecd182fb5e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Mar 2026 20:19:01 +0100 Subject: [PATCH 222/236] Update Debian kernel to v6.19.8 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index eba00afe5e..739c6bcc82 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ -KERNEL_VERSION="6.19.7" +KERNEL_VERSION="6.19.8" KERNEL_REVISION="1" KERNEL_LOCALVERSION="-surface" From 18809cb00a1bd03d73a7b6dfbf0ab6d540287c6d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Mar 2026 20:21:42 +0100 Subject: [PATCH 223/236] Update Fedora kernels to v6.19.8 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index 87b681d2fe..a935921d67 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -19,7 +19,7 @@ ## Fedora tags: kernel-X.Y.Z ## Upstream tags: vX.Y.Z ## -PACKAGE_TAG = "kernel-6.19.7-0" +PACKAGE_TAG = "kernel-6.19.8-0" ## ## The release number of the modified kernel package. From ad745c3f59b624261238da732acdadb06f87dc5c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 15 Mar 2026 20:24:54 +0100 Subject: [PATCH 224/236] Update Arch kernel to v6.19.8 --- pkg/arch/kernel/0001-secureboot.patch | 2 +- pkg/arch/kernel/0002-surface3.patch | 2 +- pkg/arch/kernel/0003-mwifiex.patch | 2 +- pkg/arch/kernel/0004-ath10k.patch | 2 +- pkg/arch/kernel/0005-ipts.patch | 2 +- pkg/arch/kernel/0006-ithc.patch | 2 +- pkg/arch/kernel/0007-surface-sam.patch | 2 +- .../kernel/0008-surface-sam-over-hid.patch | 2 +- pkg/arch/kernel/0009-surface-button.patch | 2 +- pkg/arch/kernel/0010-surface-typecover.patch | 2 +- pkg/arch/kernel/0011-surface-shutdown.patch | 2 +- pkg/arch/kernel/0012-surface-gpe.patch | 2 +- pkg/arch/kernel/0013-cameras.patch | 2 +- pkg/arch/kernel/0014-amd-gpio.patch | 2 +- pkg/arch/kernel/0015-rtc.patch | 2 +- pkg/arch/kernel/0016-hid-surface.patch | 2 +- pkg/arch/kernel/0017-powercap.patch | 1 - pkg/arch/kernel/PKGBUILD | 38 +++++++++---------- pkg/arch/kernel/surface.config | 2 +- 19 files changed, 35 insertions(+), 38 deletions(-) delete mode 120000 pkg/arch/kernel/0017-powercap.patch diff --git a/pkg/arch/kernel/0001-secureboot.patch b/pkg/arch/kernel/0001-secureboot.patch index 5b0195eb8d..4516acec25 120000 --- a/pkg/arch/kernel/0001-secureboot.patch +++ b/pkg/arch/kernel/0001-secureboot.patch @@ -1 +1 @@ -../../../patches/6.18/0001-secureboot.patch \ No newline at end of file +../../../patches/6.19/0001-secureboot.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0002-surface3.patch b/pkg/arch/kernel/0002-surface3.patch index 35e0ba2241..833fd566aa 120000 --- a/pkg/arch/kernel/0002-surface3.patch +++ b/pkg/arch/kernel/0002-surface3.patch @@ -1 +1 @@ -../../../patches/6.18/0002-surface3.patch \ No newline at end of file +../../../patches/6.19/0002-surface3.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0003-mwifiex.patch b/pkg/arch/kernel/0003-mwifiex.patch index 64548e7d9d..21224efb0d 120000 --- a/pkg/arch/kernel/0003-mwifiex.patch +++ b/pkg/arch/kernel/0003-mwifiex.patch @@ -1 +1 @@ -../../../patches/6.18/0003-mwifiex.patch \ No newline at end of file +../../../patches/6.19/0003-mwifiex.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0004-ath10k.patch b/pkg/arch/kernel/0004-ath10k.patch index 52693d8bb3..8a68a0883b 120000 --- a/pkg/arch/kernel/0004-ath10k.patch +++ b/pkg/arch/kernel/0004-ath10k.patch @@ -1 +1 @@ -../../../patches/6.18/0004-ath10k.patch \ No newline at end of file +../../../patches/6.19/0004-ath10k.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0005-ipts.patch b/pkg/arch/kernel/0005-ipts.patch index 255fbd10cf..518075814e 120000 --- a/pkg/arch/kernel/0005-ipts.patch +++ b/pkg/arch/kernel/0005-ipts.patch @@ -1 +1 @@ -../../../patches/6.18/0005-ipts.patch \ No newline at end of file +../../../patches/6.19/0005-ipts.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0006-ithc.patch b/pkg/arch/kernel/0006-ithc.patch index fc3080a983..8976bdd92f 120000 --- a/pkg/arch/kernel/0006-ithc.patch +++ b/pkg/arch/kernel/0006-ithc.patch @@ -1 +1 @@ -../../../patches/6.18/0006-ithc.patch \ No newline at end of file +../../../patches/6.19/0006-ithc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0007-surface-sam.patch b/pkg/arch/kernel/0007-surface-sam.patch index 6c09d90243..b8d7b6b21c 120000 --- a/pkg/arch/kernel/0007-surface-sam.patch +++ b/pkg/arch/kernel/0007-surface-sam.patch @@ -1 +1 @@ -../../../patches/6.18/0007-surface-sam.patch \ No newline at end of file +../../../patches/6.19/0007-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0008-surface-sam-over-hid.patch b/pkg/arch/kernel/0008-surface-sam-over-hid.patch index 08f79dcde2..1455937a99 120000 --- a/pkg/arch/kernel/0008-surface-sam-over-hid.patch +++ b/pkg/arch/kernel/0008-surface-sam-over-hid.patch @@ -1 +1 @@ -../../../patches/6.18/0008-surface-sam-over-hid.patch \ No newline at end of file +../../../patches/6.19/0008-surface-sam-over-hid.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0009-surface-button.patch b/pkg/arch/kernel/0009-surface-button.patch index 7ff9dad876..909b1d04f6 120000 --- a/pkg/arch/kernel/0009-surface-button.patch +++ b/pkg/arch/kernel/0009-surface-button.patch @@ -1 +1 @@ -../../../patches/6.18/0009-surface-button.patch \ No newline at end of file +../../../patches/6.19/0009-surface-button.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0010-surface-typecover.patch b/pkg/arch/kernel/0010-surface-typecover.patch index 9671bcc9b5..069260bbfb 120000 --- a/pkg/arch/kernel/0010-surface-typecover.patch +++ b/pkg/arch/kernel/0010-surface-typecover.patch @@ -1 +1 @@ -../../../patches/6.18/0010-surface-typecover.patch \ No newline at end of file +../../../patches/6.19/0010-surface-typecover.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0011-surface-shutdown.patch b/pkg/arch/kernel/0011-surface-shutdown.patch index 301ed6896e..326c804c73 120000 --- a/pkg/arch/kernel/0011-surface-shutdown.patch +++ b/pkg/arch/kernel/0011-surface-shutdown.patch @@ -1 +1 @@ -../../../patches/6.18/0011-surface-shutdown.patch \ No newline at end of file +../../../patches/6.19/0011-surface-shutdown.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0012-surface-gpe.patch b/pkg/arch/kernel/0012-surface-gpe.patch index 36c0968268..56affad1e5 120000 --- a/pkg/arch/kernel/0012-surface-gpe.patch +++ b/pkg/arch/kernel/0012-surface-gpe.patch @@ -1 +1 @@ -../../../patches/6.18/0012-surface-gpe.patch \ No newline at end of file +../../../patches/6.19/0012-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0013-cameras.patch b/pkg/arch/kernel/0013-cameras.patch index a558b038bf..c979cf4a3b 120000 --- a/pkg/arch/kernel/0013-cameras.patch +++ b/pkg/arch/kernel/0013-cameras.patch @@ -1 +1 @@ -../../../patches/6.18/0013-cameras.patch \ No newline at end of file +../../../patches/6.19/0013-cameras.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0014-amd-gpio.patch b/pkg/arch/kernel/0014-amd-gpio.patch index 26387d23f1..7d9126a952 120000 --- a/pkg/arch/kernel/0014-amd-gpio.patch +++ b/pkg/arch/kernel/0014-amd-gpio.patch @@ -1 +1 @@ -../../../patches/6.18/0014-amd-gpio.patch \ No newline at end of file +../../../patches/6.19/0014-amd-gpio.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0015-rtc.patch b/pkg/arch/kernel/0015-rtc.patch index ab76e5fea1..4f02fc9c71 120000 --- a/pkg/arch/kernel/0015-rtc.patch +++ b/pkg/arch/kernel/0015-rtc.patch @@ -1 +1 @@ -../../../patches/6.18/0015-rtc.patch \ No newline at end of file +../../../patches/6.19/0015-rtc.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0016-hid-surface.patch b/pkg/arch/kernel/0016-hid-surface.patch index 721d18b34c..a2a8ad71df 120000 --- a/pkg/arch/kernel/0016-hid-surface.patch +++ b/pkg/arch/kernel/0016-hid-surface.patch @@ -1 +1 @@ -../../../patches/6.18/0016-hid-surface.patch \ No newline at end of file +../../../patches/6.19/0016-hid-surface.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0017-powercap.patch b/pkg/arch/kernel/0017-powercap.patch deleted file mode 120000 index 4e00a36f8d..0000000000 --- a/pkg/arch/kernel/0017-powercap.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/6.18/0017-powercap.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index c192df9ec8..4f66be085a 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -3,7 +3,7 @@ # Maintainer: Jan Alexander Steffens (heftig) pkgbase=linux-surface -pkgver=6.18.8.arch2 +pkgver=6.19.8.arch1 pkgrel=1 pkgdesc='Linux' _shortver=${pkgver%.*} @@ -58,34 +58,32 @@ source=( 0014-amd-gpio.patch 0015-rtc.patch 0016-hid-surface.patch - 0017-powercap.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman 'A2FF3A36AAA56654109064AB19802F8B0D70FC30' # Jan Alexander Steffens (heftig) ) -sha256sums=('9526800a611ea4a46e8410686c89bab5a92df4b556b853e8933caa0d6cca835a' +sha256sums=('4d1e35866e69aaef26812c1cc5651936faa5e360b5ef6a19c28fb19b6848ab4b' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' - '25457105444c91e4de57c6938f4e36f98e2ce1d6f079b401ae8d6c2ada689c06' - 'a813b8fda4a4eadd13ad78fac982aba0abcad72398cd9989eaafcc8372d3d39b' - 'a421e02dcbad81ec20e7c0e9c83a26ea018b203d0da96090cce25f8da6c63982' - 'e3022dbf12cf2e24fe0be1777da129808d9827be89e09d34f4971c5bfda53972' - '4b2972e73d311ac9f603e9229491464439a36537666f426797dcc70ecc611a4b' - '7b908157f3c88a16106555513d36c00a20ceec78314600b9ad042c8e62a7a90a' - '33347c5a7c7112ad08d83dbb54d0841c1044c62c9695a40a3cf09a54a65c4684' - 'c77726fee303a204f05385cacd6644a3e3452580056391d11873919b18ca5efb' - 'e40a928da09249e35f40072bee54f61a0b5d9aea12917674fa9c4a3944072e2b' - 'b6badd94dc5157c88ed64d34a38a4333d0cc6b19190d179a57a5a2fb3248bc24' - '3722b78f24f19d653849864fc2ae24c782a2c83519620551191b96bcaac1a3cb' - 'aa9601d0e3e8c5268c3e975632e8de93e001515b25b8c0caf2c0428907783c68' - 'aaabc6fe397ad534e0d1654ffafefe8aebd9b8cbb52d05b0abb0c394e1dce650' - 'beff0cf807dfbcbe58505f9d101a910679e360a11bb82ce9194db367c844ea7c' - '34ce59aa1f32cdcbb48307cbdc06de27376c909938fb6f8647c3dc47f859aac6' - 'bb2c5d4718eba576037d7d8c59dbd0227cadf5184b644071e26d441b38911e77' - '4e5876d308e391fc2055a6b1671d8af0bb394e81e05bede7edcc829ab6ba3059') + '5113eaf632692852082972ff881321428b060efd4ff0177c2ce3c72c64ad76e7' + 'dbad1231a9a0a2bcf4f6567149e5b86f82f4bb29a3b3fa91543b1996e66353f4' + 'a209e3e9c907a5b8803b841e1636eb18e849ff812f29fcff8ba57b140ccb5474' + '516babc082c6e21c1e842e5abdfd3e882c6f6e1039a4a909d68cd635100b95a3' + 'ccc2f38598d9a49e19aa88d01c797654468b86f07beda4d355067a9d9083880e' + 'e917bf758d93bdd3ee0836d4314849aada9a0902cd0161e1f357f71953221101' + '33871bca7d63230902b6c0e41460c295266fb3aaf31a57857666c55775efa560' + '32589bbccf6672e427f91cdc991be2c3d4270969763a79c6c1edef8f9c9ab5b5' + 'd7b7856ef1693bb8633748e647f551d84a6dd2070abdc75340dd8bcba98eada7' + '5617c0fb8ae0db1de3865aafb65b21d7b5b5e5857d4baa34c1c17f2a2e502485' + '64509e957756d942d5561801123cf456e8caa1aa44bd69c2d5f97093c4830f9f' + 'df547b8697f058fcfd9ae082a2ae4a87cd4ae5d7dae70129889da00219db4733' + 'dbaddf5ed1ec7aec515867facd17a09e083289eb4185b3af4f3bc1d6c9bd1ad7' + '1d703ad95120df846d77b0c5338af1829119e2bfcac258ebedf0145ba02e22f3' + '76b91256a525c4f626802b5ad29ddb1a9477bc90001c9ea8c469ae77d07593fc' + '32b91e80ddc124dc7f31bbde65fcb18fa7a7f194f953ccfc8f14d630aac4ddc4') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/arch/kernel/surface.config b/pkg/arch/kernel/surface.config index cb40098f0f..fae801b7ff 120000 --- a/pkg/arch/kernel/surface.config +++ b/pkg/arch/kernel/surface.config @@ -1 +1 @@ -../../../configs/surface-6.18.config \ No newline at end of file +../../../configs/surface-6.19.config \ No newline at end of file From 321be2e7ebbb751153a97c6ed38836f2f4300dc6 Mon Sep 17 00:00:00 2001 From: surfacebot Date: Sun, 15 Mar 2026 19:24:24 +0000 Subject: [PATCH 225/236] patches/v6.12: Update to v6.12.77 Generated 14 patches from linux-surface/kernel branch v6.12-surface Base version: v6.12.77 Branch: v6.12-surface Automatically generated patches using git-format-patchsets. --- patches/6.12/0001-secureboot.patch | 4 +- patches/6.12/0002-surface3-oemb.patch | 2 +- patches/6.12/0003-mwifiex.patch | 6 +- patches/6.12/0004-ath10k.patch | 2 +- patches/6.12/0005-ipts.patch | 6 +- patches/6.12/0006-ithc.patch | 4 +- patches/6.12/0007-surface-sam-over-hid.patch | 4 +- patches/6.12/0008-surface-button.patch | 4 +- patches/6.12/0009-surface-typecover.patch | 76 ++++++++++---------- patches/6.12/0010-surface-shutdown.patch | 2 +- patches/6.12/0011-surface-gpe.patch | 2 +- patches/6.12/0012-cameras.patch | 20 +++--- patches/6.12/0013-amd-gpio.patch | 14 ++-- patches/6.12/0014-rtc.patch | 2 +- 14 files changed, 74 insertions(+), 74 deletions(-) diff --git a/patches/6.12/0001-secureboot.patch b/patches/6.12/0001-secureboot.patch index 4a6a08655c..a3bd6c703f 100644 --- a/patches/6.12/0001-secureboot.patch +++ b/patches/6.12/0001-secureboot.patch @@ -1,4 +1,4 @@ -From 8d09002d4356483485c2580ca87a34b5f3d361c8 Mon Sep 17 00:00:00 2001 +From d78b9a6c4a99464f0a4a6317d4a44e22c129a83a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -35,7 +35,7 @@ index b5c79f433..a1bbedd98 100644 -- 2.53.0 -From 3f9e289841c6166e784ddae3bd16d7b8d3c2a488 Mon Sep 17 00:00:00 2001 +From ba56e2f141004eecd63bfe191126568bbb50d5fe Mon Sep 17 00:00:00 2001 From: "J. Eduardo" Date: Sun, 25 Aug 2024 14:17:45 +0200 Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter diff --git a/patches/6.12/0002-surface3-oemb.patch b/patches/6.12/0002-surface3-oemb.patch index 1edcaa2c56..0df608f40a 100644 --- a/patches/6.12/0002-surface3-oemb.patch +++ b/patches/6.12/0002-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 888c10ccdb9f32091ab3ec94abcae8698c0557c1 Mon Sep 17 00:00:00 2001 +From 242ddda76132ccbb78fce0c338bd7805ffa371bd Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/6.12/0003-mwifiex.patch b/patches/6.12/0003-mwifiex.patch index ebd2028f22..be0bc6e380 100644 --- a/patches/6.12/0003-mwifiex.patch +++ b/patches/6.12/0003-mwifiex.patch @@ -1,4 +1,4 @@ -From 4afbb30efe35caec71dc68fdc6dab46f67961cc5 Mon Sep 17 00:00:00 2001 +From b5f73cc1b4a0cdec1a5e311dd1d79a0e19ea1361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -165,7 +165,7 @@ index d6ff964ae..5d30ae39d 100644 -- 2.53.0 -From da5716d67e5f0150bc07cf44da06fbb4d894069e Mon Sep 17 00:00:00 2001 +From 259acade815fa5cdb5067eeac2442c26b4ceb2c6 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -320,7 +320,7 @@ index 5d30ae39d..c14eb56eb 100644 -- 2.53.0 -From d2505cd7d32b5fc5b81382c4cbc1ce1393a57f76 Mon Sep 17 00:00:00 2001 +From eed389098afc172e91855287538ca1bbd3d11a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell diff --git a/patches/6.12/0004-ath10k.patch b/patches/6.12/0004-ath10k.patch index f2176eb692..bca978e97e 100644 --- a/patches/6.12/0004-ath10k.patch +++ b/patches/6.12/0004-ath10k.patch @@ -1,4 +1,4 @@ -From 4a5651c06050c41d04ca79d4a47d4c6b771b3a7b Mon Sep 17 00:00:00 2001 +From 4125e5a84b2370376ab1c108fbff63ccee48d3b0 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files diff --git a/patches/6.12/0005-ipts.patch b/patches/6.12/0005-ipts.patch index 9580eb3df2..af6bf2fea5 100644 --- a/patches/6.12/0005-ipts.patch +++ b/patches/6.12/0005-ipts.patch @@ -1,4 +1,4 @@ -From 23fbf7dcdeb0f2b04cbcdaa14a5b4b1b63d797b1 Mon Sep 17 00:00:00 2001 +From 4dbb2841ec84f5c7612d22baffe291f7e5b1c74e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -37,7 +37,7 @@ index 1e4edf896..61d1a8816 100644 -- 2.53.0 -From 81895e560ee812ca707b39bb92de5fe4197c5815 Mon Sep 17 00:00:00 2001 +From 77f4b43a690d491d4be35f52d334e07f24162958 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -144,7 +144,7 @@ index d4f852f71..b76109d5d 100644 -- 2.53.0 -From 59ce30668370602d988bcb7b3717aa8c057bdd63 Mon Sep 17 00:00:00 2001 +From 8df48859297fd0730bf9d231343176cd6f2ecedd Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus diff --git a/patches/6.12/0006-ithc.patch b/patches/6.12/0006-ithc.patch index 928198b6c3..b6aa38071a 100644 --- a/patches/6.12/0006-ithc.patch +++ b/patches/6.12/0006-ithc.patch @@ -1,4 +1,4 @@ -From 673e3507f514ee0a6b63ab549f25d4507740f0cf Mon Sep 17 00:00:00 2001 +From 10da29a50dc86540c5162137ed52c5c99823b185 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -39,7 +39,7 @@ index 066e4cd6e..7b320d09d 100644 -- 2.53.0 -From 57ccc0251fe2fa2f424ead18d85832fbe4ceeca0 Mon Sep 17 00:00:00 2001 +From db66ed7a0570276e8d561777fa3ba2f97bd449c6 Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller diff --git a/patches/6.12/0007-surface-sam-over-hid.patch b/patches/6.12/0007-surface-sam-over-hid.patch index 3992272d7f..aa3b763500 100644 --- a/patches/6.12/0007-surface-sam-over-hid.patch +++ b/patches/6.12/0007-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 5a87dd60193963c9b28a9a58e27217f4fda90145 Mon Sep 17 00:00:00 2001 +From 04627863b4690e94b904bdebd26e1532b6112c26 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index f43067f67..1761ca30e 100644 -- 2.53.0 -From c04b0d4d8b4182b4302b0f03df1454eab9a792fa Mon Sep 17 00:00:00 2001 +From 1d7c291867bb34ababa60243f125c26da2ec85e9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch diff --git a/patches/6.12/0008-surface-button.patch b/patches/6.12/0008-surface-button.patch index 92df850eae..b7eb4350cd 100644 --- a/patches/6.12/0008-surface-button.patch +++ b/patches/6.12/0008-surface-button.patch @@ -1,4 +1,4 @@ -From af3f8f3a86740d0caa85e21b8d9a7c2b672906a9 Mon Sep 17 00:00:00 2001 +From 82584739abaac5bfc5adfaeb3ea03facf77de7ce Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -75,7 +75,7 @@ index 5c5d407fe..4e1bfe90e 100644 -- 2.53.0 -From 6b7a4c7cd572993123287ab4f26f48c86ec0aa92 Mon Sep 17 00:00:00 2001 +From d5ecaa5cb6ac3a5eeb443b8bae1dc077df4bda75 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd diff --git a/patches/6.12/0009-surface-typecover.patch b/patches/6.12/0009-surface-typecover.patch index 94b5e331db..edf1f9c2dc 100644 --- a/patches/6.12/0009-surface-typecover.patch +++ b/patches/6.12/0009-surface-typecover.patch @@ -1,4 +1,4 @@ -From f08f3e9ed0542ec70e6f88b7b34b9e4168f020fd Mon Sep 17 00:00:00 2001 +From 142804a88c118139dcc4f69ed27717e6d5c8156f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -39,7 +39,7 @@ index 323a949bb..abc2cdecd 100644 -- 2.53.0 -From ee707a758d5556280365f8af197a4ae9845a8d76 Mon Sep 17 00:00:00 2001 +From 74b286ffe37d7836327742b71f78f00880412a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -75,7 +75,7 @@ Patchset: surface-typecover 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index c3a914458..6ca3a3684 100644 +index eb1489884..0a6cf8926 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -34,7 +34,10 @@ @@ -97,11 +97,11 @@ index c3a914458..6ca3a3684 100644 /* quirks to control the device */ #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) -@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) +@@ -73,12 +77,15 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_DISABLE_WAKEUP BIT(21) #define MT_QUIRK_ORIENTATION_INVERT BIT(22) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) + #define MT_QUIRK_YOGABOOK9I BIT(24) ++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -113,7 +113,7 @@ index c3a914458..6ca3a3684 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, HID_LATENCY_HIGH = 1, -@@ -171,6 +178,8 @@ struct mt_device { +@@ -172,6 +179,8 @@ struct mt_device { struct list_head applications; struct list_head reports; @@ -122,16 +122,16 @@ index c3a914458..6ca3a3684 100644 }; static void mt_post_parse_default_settings(struct mt_device *td, -@@ -215,6 +224,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_GOOGLE 0x0111 - #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 +@@ -218,6 +227,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_SMART_TECH 0x0113 -+#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114 + #define MT_CLS_YOGABOOK9I 0x0115 + #define MT_CLS_EGALAX_P80H84 0x0116 ++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0117 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 -@@ -406,6 +416,16 @@ static const struct mt_class mt_classes[] = { - MT_QUIRK_ALWAYS_VALID | +@@ -422,6 +432,16 @@ static const struct mt_class mt_classes[] = { + MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_CONTACT_CNT_ACCURATE, }, + { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, @@ -147,7 +147,7 @@ index c3a914458..6ca3a3684 100644 { } }; -@@ -1764,6 +1784,69 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1836,6 +1856,69 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -217,7 +217,7 @@ index c3a914458..6ca3a3684 100644 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; -@@ -1787,6 +1870,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1859,6 +1942,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; hid_set_drvdata(hdev, td); @@ -227,7 +227,7 @@ index c3a914458..6ca3a3684 100644 INIT_LIST_HEAD(&td->applications); INIT_LIST_HEAD(&td->reports); -@@ -1825,8 +1911,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1897,8 +1983,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -239,7 +239,7 @@ index c3a914458..6ca3a3684 100644 if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) mt_fix_const_fields(hdev, HID_DG_CONTACTID); -@@ -1835,8 +1923,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +@@ -1907,8 +1995,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_NOGET; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); @@ -251,7 +251,7 @@ index c3a914458..6ca3a3684 100644 ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); if (ret) -@@ -1886,6 +1976,7 @@ static void mt_remove(struct hid_device *hdev) +@@ -1958,6 +2048,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); @@ -259,7 +259,7 @@ index c3a914458..6ca3a3684 100644 del_timer_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); -@@ -2318,6 +2409,11 @@ static const struct hid_device_id mt_devices[] = { +@@ -2397,6 +2488,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, @@ -274,7 +274,7 @@ index c3a914458..6ca3a3684 100644 -- 2.53.0 -From 0000b5cb26788fb71b8adfda9621f8f6afc83225 Mon Sep 17 00:00:00 2001 +From 51b8f39ff7aaf9ef241f95ec40f727f55440c5e7 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -303,18 +303,18 @@ Patchset: surface-typecover 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 6ca3a3684..5c6ae7de7 100644 +index 0a6cf8926..6518bb81b 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c -@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) +@@ -78,6 +78,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_ORIENTATION_INVERT BIT(22) - #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) -+#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + #define MT_QUIRK_YOGABOOK9I BIT(24) + #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(25) ++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(26) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL"); +@@ -85,6 +86,8 @@ MODULE_LICENSE("GPL"); #define MT_BUTTONTYPE_CLICKPAD 0 #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 @@ -323,7 +323,7 @@ index 6ca3a3684..5c6ae7de7 100644 enum latency_mode { HID_LATENCY_NORMAL = 0, -@@ -418,6 +421,7 @@ static const struct mt_class mt_classes[] = { +@@ -434,6 +437,7 @@ static const struct mt_class mt_classes[] = { }, { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER, .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT | @@ -331,7 +331,7 @@ index 6ca3a3684..5c6ae7de7 100644 MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | -@@ -1396,6 +1400,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1412,6 +1416,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_SYSTEM_MULTIAXIS && @@ -341,7 +341,7 @@ index 6ca3a3684..5c6ae7de7 100644 !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; -@@ -1423,6 +1430,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, +@@ -1439,6 +1446,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } @@ -363,7 +363,7 @@ index 6ca3a3684..5c6ae7de7 100644 if (rdata->is_mt_collection) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); -@@ -1444,6 +1466,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1460,6 +1482,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_report_data *rdata; @@ -371,7 +371,7 @@ index 6ca3a3684..5c6ae7de7 100644 rdata = mt_find_report_data(td, field->report); if (rdata && rdata->is_mt_collection) { -@@ -1451,6 +1474,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, +@@ -1467,6 +1490,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } @@ -391,7 +391,7 @@ index 6ca3a3684..5c6ae7de7 100644 /* let hid-core decide for the others */ return 0; } -@@ -1460,11 +1496,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, +@@ -1476,11 +1512,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); struct mt_report_data *rdata; @@ -413,7 +413,7 @@ index 6ca3a3684..5c6ae7de7 100644 return 0; } -@@ -1649,6 +1695,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) +@@ -1697,6 +1743,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app) app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -456,7 +456,7 @@ index 6ca3a3684..5c6ae7de7 100644 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); -@@ -1698,6 +1780,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +@@ -1746,6 +1828,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); break; @@ -470,7 +470,7 @@ index 6ca3a3684..5c6ae7de7 100644 default: suffix = "UNKNOWN"; break; -@@ -1784,30 +1873,6 @@ static void mt_expired_timeout(struct timer_list *t) +@@ -1856,30 +1945,6 @@ static void mt_expired_timeout(struct timer_list *t) clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } @@ -501,7 +501,7 @@ index 6ca3a3684..5c6ae7de7 100644 static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) { struct usb_device *udev = hid_to_usb_dev(hdev); -@@ -1816,8 +1881,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) +@@ -1888,8 +1953,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled) /* Wake up the device in case it's already suspended */ pm_runtime_get_sync(&udev->dev); @@ -513,7 +513,7 @@ index 6ca3a3684..5c6ae7de7 100644 hid_err(hdev, "couldn't find backlight field\n"); goto out; } -@@ -1954,13 +2020,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) +@@ -2026,13 +2092,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { @@ -538,7 +538,7 @@ index 6ca3a3684..5c6ae7de7 100644 /* Some Elan legacy devices require SET_IDLE to be set on resume. * It should be safe to send it to other devices too. * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ -@@ -1969,12 +2046,31 @@ static int mt_resume(struct hid_device *hdev) +@@ -2041,12 +2118,31 @@ static int mt_resume(struct hid_device *hdev) mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); diff --git a/patches/6.12/0010-surface-shutdown.patch b/patches/6.12/0010-surface-shutdown.patch index b97aa772be..5a97d6225f 100644 --- a/patches/6.12/0010-surface-shutdown.patch +++ b/patches/6.12/0010-surface-shutdown.patch @@ -1,4 +1,4 @@ -From 28467a583271770d1ea372a210a6b7ab50cf756e Mon Sep 17 00:00:00 2001 +From fe77fe0cb314d0202ca005b064c439e96b7a5920 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod diff --git a/patches/6.12/0011-surface-gpe.patch b/patches/6.12/0011-surface-gpe.patch index eb87ee1ce2..5ec1a054f7 100644 --- a/patches/6.12/0011-surface-gpe.patch +++ b/patches/6.12/0011-surface-gpe.patch @@ -1,4 +1,4 @@ -From 9cef4331e693b13fc22809d5c628dda9b1ffcf24 Mon Sep 17 00:00:00 2001 +From d199f675da076339d1617e2562f714d791010959 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 diff --git a/patches/6.12/0012-cameras.patch b/patches/6.12/0012-cameras.patch index a47bd937cb..4aee5ab8eb 100644 --- a/patches/6.12/0012-cameras.patch +++ b/patches/6.12/0012-cameras.patch @@ -1,4 +1,4 @@ -From 06a44113561fcebaf07821e7345c9b2ca7e783f1 Mon Sep 17 00:00:00 2001 +From cb78d8125731975857cacbb981babad2563f6133 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -74,7 +74,7 @@ index ba98763ce..6021907ec 100644 -- 2.53.0 -From 59e69a436cb8a5ea01ec61500a3815610d70648c Mon Sep 17 00:00:00 2001 +From 4896c5dd64257633ca4d42237f17f0ae37edeafe Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -184,7 +184,7 @@ index b76109d5d..06b2d4a85 100644 -- 2.53.0 -From 946fd9985e3144bf7cf8d9d11b96602d4189baab Mon Sep 17 00:00:00 2001 +From 3500e8e7e174ca3d2a4e0659263570633ea40818 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -221,7 +221,7 @@ index 81ac4c691..f453c9043 100644 -- 2.53.0 -From a438b4f3aca63561f32460cd0400e2d1548189fa Mon Sep 17 00:00:00 2001 +From 09848cfdbb28c7cb8ef310661ef84aea2b2d5571 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -277,7 +277,7 @@ index 9e69ac9cf..d6003198a 100644 -- 2.53.0 -From e321ee96d9a8c08f02466f893ce80762bd349182 Mon Sep 17 00:00:00 2001 +From 19f7efbb8c697246464d4556715776e81713266a Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -316,7 +316,7 @@ index 3226888d7..3bfe45b76 100644 -- 2.53.0 -From 06d53e5e1461d11f3e2f38a41a37c0d0d6aeef4d Mon Sep 17 00:00:00 2001 +From d73081eebba9db15ff01cb6208ec6f6a4fee7993 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -367,7 +367,7 @@ index f19c8adf2..923ed1b5a 100644 -- 2.53.0 -From 4ba987eb946b3cd99ff66e1d795fcfed122d48e9 Mon Sep 17 00:00:00 2001 +From 36fb55a4db8fc2fa00db4b21351a197a556837c2 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -408,7 +408,7 @@ index f453c9043..b8ad6b413 100644 -- 2.53.0 -From 6644e392bf583e2e9ecec68344a1b92b03d990d6 Mon Sep 17 00:00:00 2001 +From 082f363ec90ef3f959e0d2196e7262bb631b48ef Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -449,7 +449,7 @@ index 7807fa329..2d2abb25b 100644 -- 2.53.0 -From 74032759acda3c94f308a238be0a16b3448271f0 Mon Sep 17 00:00:00 2001 +From ce274f610494db183eb9af63caf7be993a213e1e Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -700,7 +700,7 @@ index 000000000..35aeb5db8 -- 2.53.0 -From ba2041730a467507a5882486d3a1e24dcf5dbee4 Mon Sep 17 00:00:00 2001 +From 265db8eb0cd4a576d4c1fc0326211c7d033ee49e Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 diff --git a/patches/6.12/0013-amd-gpio.patch b/patches/6.12/0013-amd-gpio.patch index ef5d1b23c2..dd24a7f7ea 100644 --- a/patches/6.12/0013-amd-gpio.patch +++ b/patches/6.12/0013-amd-gpio.patch @@ -1,4 +1,4 @@ -From bc7f7eb5a3275b16cad8ef38a4d52bcb01a2eaed Mon Sep 17 00:00:00 2001 +From bf7336bc7535b912923ac679762f78a547507371 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -21,7 +21,7 @@ Patchset: amd-gpio 1 file changed, 17 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 63adda8a1..00914222a 100644 +index a1acff778..8cb5d2c5f 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -32,7 +32,7 @@ index 63adda8a1..00914222a 100644 #include -@@ -1174,6 +1175,17 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1178,6 +1179,17 @@ static void __init mp_config_acpi_legacy_irqs(void) } } @@ -50,7 +50,7 @@ index 63adda8a1..00914222a 100644 /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -@@ -1229,6 +1241,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) +@@ -1233,6 +1245,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, acpi_gbl_FADT.sci_interrupt); @@ -65,7 +65,7 @@ index 63adda8a1..00914222a 100644 -- 2.53.0 -From 0535786e28e68e0ccf56d7f19964b55daeea9a46 Mon Sep 17 00:00:00 2001 +From 2bc288e1402dd22595170a9bf212395dd27982e6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -80,10 +80,10 @@ Patchset: amd-gpio 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 00914222a..2b35bb58b 100644 +index 8cb5d2c5f..84ad15d6d 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -1177,12 +1177,19 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1181,12 +1181,19 @@ static void __init mp_config_acpi_legacy_irqs(void) static const struct dmi_system_id surface_quirk[] __initconst = { { diff --git a/patches/6.12/0014-rtc.patch b/patches/6.12/0014-rtc.patch index ac7b7f3087..54c58b72ed 100644 --- a/patches/6.12/0014-rtc.patch +++ b/patches/6.12/0014-rtc.patch @@ -1,4 +1,4 @@ -From adecaa7f69aa83db889422a5e6ecb5a34f785842 Mon Sep 17 00:00:00 2001 +From 1d252cfb63fc691888327a706233fb81f28d29ee Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms From 29c7e6e9cd5e2d8bd87360c4f9e387829c63f3ba Mon Sep 17 00:00:00 2001 From: bagratte Date: Sat, 18 Apr 2026 15:25:50 +0400 Subject: [PATCH 226/236] .github: Remove 'Maximize disk space' --- .github/workflows/arch.yml | 12 ++---------- .github/workflows/debian.yml | 8 -------- .github/workflows/fedora-40.yml | 8 -------- .github/workflows/fedora-41.yml | 8 -------- .github/workflows/fedora-42.yml | 8 -------- .github/workflows/fedora-43.yml | 8 -------- .github/workflows/rebase-kernel.yml | 9 --------- 7 files changed, 2 insertions(+), 59 deletions(-) diff --git a/.github/workflows/arch.yml b/.github/workflows/arch.yml index 240021f6f6..fde0d38346 100644 --- a/.github/workflows/arch.yml +++ b/.github/workflows/arch.yml @@ -10,20 +10,12 @@ on: repository_dispatch: workflow_dispatch: - + jobs: build: name: Build Kernel runs-on: ubuntu-latest steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 5120 - remove-dotnet: true - remove-android: true - remove-docker-images: true - - name: Checkout code uses: actions/checkout@v6 @@ -121,4 +113,4 @@ jobs: -e BRANCH_STAGING \ -e GITHUB_REPOSITORY \ -- \ - bash ./.github/scripts/repository/arch.sh \ No newline at end of file + bash ./.github/scripts/repository/arch.sh diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 9024a86ce7..38f5eac527 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -16,14 +16,6 @@ jobs: name: Build Kernel runs-on: ubuntu-latest steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 5120 - remove-dotnet: true - remove-android: true - remove-docker-images: true - - name: Checkout code uses: actions/checkout@v6 diff --git a/.github/workflows/fedora-40.yml b/.github/workflows/fedora-40.yml index 7fc2aaa079..85846ec8b5 100644 --- a/.github/workflows/fedora-40.yml +++ b/.github/workflows/fedora-40.yml @@ -17,14 +17,6 @@ jobs: name: Build Kernel runs-on: ubuntu-latest steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 5120 - remove-dotnet: true - remove-android: true - remove-docker-images: true - - name: Checkout code uses: actions/checkout@v6 diff --git a/.github/workflows/fedora-41.yml b/.github/workflows/fedora-41.yml index 744b4a211f..0ffcd79446 100644 --- a/.github/workflows/fedora-41.yml +++ b/.github/workflows/fedora-41.yml @@ -17,14 +17,6 @@ jobs: name: Build Kernel runs-on: ubuntu-latest steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 5120 - remove-dotnet: true - remove-android: true - remove-docker-images: true - - name: Checkout code uses: actions/checkout@v6 diff --git a/.github/workflows/fedora-42.yml b/.github/workflows/fedora-42.yml index 7a856f7088..b6bda5eeba 100644 --- a/.github/workflows/fedora-42.yml +++ b/.github/workflows/fedora-42.yml @@ -17,14 +17,6 @@ jobs: name: Build Kernel runs-on: ubuntu-latest steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 5120 - remove-dotnet: true - remove-android: true - remove-docker-images: true - - name: Checkout code uses: actions/checkout@v6 diff --git a/.github/workflows/fedora-43.yml b/.github/workflows/fedora-43.yml index b3fb6dd838..9d31021281 100644 --- a/.github/workflows/fedora-43.yml +++ b/.github/workflows/fedora-43.yml @@ -17,14 +17,6 @@ jobs: name: Build Kernel runs-on: ubuntu-latest steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 5120 - remove-dotnet: true - remove-android: true - remove-docker-images: true - - name: Checkout code uses: actions/checkout@v6 diff --git a/.github/workflows/rebase-kernel.yml b/.github/workflows/rebase-kernel.yml index cb6446dfdf..9364c47096 100644 --- a/.github/workflows/rebase-kernel.yml +++ b/.github/workflows/rebase-kernel.yml @@ -34,15 +34,6 @@ jobs: runs-on: ubuntu-latest steps: - - name: Maximize disk space - uses: easimon/maximize-build-space@master - with: - root-reserve-mb: 10240 # Reserve 10GB for build - remove-dotnet: true - remove-android: true - remove-docker-images: true - remove-haskell: true - - name: Checkout linux-surface repo uses: actions/checkout@v6 with: From 029e7e8601fe35f0b038cf25d80860932cd718e5 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Apr 2026 12:29:56 +0200 Subject: [PATCH 227/236] configs: Disable the algif_aead module to fix CVE-2026-31431 --- configs/surface-6.18.config | 6 ++++++ configs/surface-6.19.config | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/configs/surface-6.18.config b/configs/surface-6.18.config index 016efc4198..6441f1b667 100644 --- a/configs/surface-6.18.config +++ b/configs/surface-6.18.config @@ -84,3 +84,9 @@ CONFIG_SURFACE_PRO3_BUTTON=m CONFIG_SURFACE_GPE=m CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m CONFIG_HID_SURFACE=m + +## +## HOTFIX FOR CVE-2026-31431 +## + +# CONFIG_CRYPTO_USER_API_AEAD is not set diff --git a/configs/surface-6.19.config b/configs/surface-6.19.config index 016efc4198..6441f1b667 100644 --- a/configs/surface-6.19.config +++ b/configs/surface-6.19.config @@ -84,3 +84,9 @@ CONFIG_SURFACE_PRO3_BUTTON=m CONFIG_SURFACE_GPE=m CONFIG_SURFACE_BOOK1_DGPU_SWITCH=m CONFIG_HID_SURFACE=m + +## +## HOTFIX FOR CVE-2026-31431 +## + +# CONFIG_CRYPTO_USER_API_AEAD is not set From 041627bb544e3c41a74cf96eb2def41eee1f5c29 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Apr 2026 13:59:40 +0200 Subject: [PATCH 228/236] pkg: arch: Rebuild with fix for CVE-2026-31431 --- pkg/arch/kernel/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 4f66be085a..ecda70f269 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -4,7 +4,7 @@ pkgbase=linux-surface pkgver=6.19.8.arch1 -pkgrel=1 +pkgrel=2 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -66,7 +66,7 @@ validpgpkeys=( ) sha256sums=('4d1e35866e69aaef26812c1cc5651936faa5e360b5ef6a19c28fb19b6848ab4b' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' - '233a1c4d898b7720dd623421b694cc030075317b01cba6444b53faefc7b2ca55' + '645003a31150560e2cd367a25c66b9957a7fefed37053c9f89960a487af86af8' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' '5113eaf632692852082972ff881321428b060efd4ff0177c2ce3c72c64ad76e7' 'dbad1231a9a0a2bcf4f6567149e5b86f82f4bb29a3b3fa91543b1996e66353f4' From 584c219ebd4396f00df79a226a11fedea51f7069 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Apr 2026 14:01:25 +0200 Subject: [PATCH 229/236] pkg: debian: Rebuild with fix for CVE-2026-31431 --- pkg/debian/kernel/version.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 739c6bcc82..8687a73b57 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ KERNEL_VERSION="6.19.8" -KERNEL_REVISION="1" +KERNEL_REVISION="2" KERNEL_LOCALVERSION="-surface" From d90b7a36360ab8303175190eb4de2bc5180caa5e Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Apr 2026 14:27:19 +0200 Subject: [PATCH 230/236] pkg: fedora: Try fixing the fedora build --- pkg/fedora/kernel-surface/configs/fedora.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/configs/fedora.config b/pkg/fedora/kernel-surface/configs/fedora.config index f71a583746..f9b5fdc3f7 100644 --- a/pkg/fedora/kernel-surface/configs/fedora.config +++ b/pkg/fedora/kernel-surface/configs/fedora.config @@ -27,7 +27,7 @@ CONFIG_SCSI_UFS_CRYPTO=y # CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set # CONFIG_SCSI_UFS_QCOM is not set # CONFIG_SCSI_UFS_HISI is not set -CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD=m CONFIG_SCSI_UFSHCD_PLATFORM=m CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_DEVFREQ_GOV_PERFORMANCE=y From dfbb631093bed1abe153c7c1d217c345d1f4f200 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Apr 2026 14:28:21 +0200 Subject: [PATCH 231/236] pkg: fedora: Rebuild with fix for CVE-2026-31431 --- pkg/fedora/kernel-surface/build-linux-surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index a935921d67..fde85dae98 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -25,7 +25,7 @@ ## The release number of the modified kernel package. ## e.g. 300 for kernel-6.3.1-300.fc38.foo ## -PACKAGE_RELEASE = "1" +PACKAGE_RELEASE = "2" ## ## Build options for configuring which parts of the kernel package are enabled. From a535303debcd9716bee421427741131e5e5f41a5 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Apr 2026 16:29:32 +0200 Subject: [PATCH 232/236] pkg: fedora: Only apply custom configs to x86 + aarch64 --- pkg/fedora/kernel-surface/build-ark.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/fedora/kernel-surface/build-ark.py b/pkg/fedora/kernel-surface/build-ark.py index 861cc7963c..2a27ba10c8 100755 --- a/pkg/fedora/kernel-surface/build-ark.py +++ b/pkg/fedora/kernel-surface/build-ark.py @@ -154,7 +154,10 @@ def system(cmd: str) -> None: print("Applying %s" % line.rstrip("\n")) - with open("redhat/configs/custom-overrides/generic/%s" % NAME, "w") as f: + with open("redhat/configs/custom-overrides/generic/x86/%s" % NAME, "w") as f: + f.write(line) + + with open("redhat/configs/custom-overrides/generic/arm/aarch64/%s" % NAME, "w") as f: f.write(line) system("git add redhat/configs/custom-overrides/generic") From 2381b6895516579b4afeb13aba81520a5dd57b06 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Apr 2026 18:03:20 +0200 Subject: [PATCH 233/236] Revert "pkg: fedora: Only apply custom configs to x86 + aarch64" This causes other problems, because our patches also add new KConfig options, that then have unexpected values on the other archs. This reverts commit a535303debcd9716bee421427741131e5e5f41a5. --- pkg/fedora/kernel-surface/build-ark.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/fedora/kernel-surface/build-ark.py b/pkg/fedora/kernel-surface/build-ark.py index 2a27ba10c8..861cc7963c 100755 --- a/pkg/fedora/kernel-surface/build-ark.py +++ b/pkg/fedora/kernel-surface/build-ark.py @@ -154,10 +154,7 @@ def system(cmd: str) -> None: print("Applying %s" % line.rstrip("\n")) - with open("redhat/configs/custom-overrides/generic/x86/%s" % NAME, "w") as f: - f.write(line) - - with open("redhat/configs/custom-overrides/generic/arm/aarch64/%s" % NAME, "w") as f: + with open("redhat/configs/custom-overrides/generic/%s" % NAME, "w") as f: f.write(line) system("git add redhat/configs/custom-overrides/generic") From 4c136ec928ce0b458562c7533852db67a8e0dc91 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Apr 2026 18:04:23 +0200 Subject: [PATCH 234/236] configs: Remove CONFIG_SCSI_UFSHCD override This is the default in all configurations that we build, and having it in the surface config makes the Fedora build really annoying, because they don't enable it on all arches. --- configs/surface-6.19.config | 6 -- .../kernel-surface/configs/fedora.config | 71 ------------------- 2 files changed, 77 deletions(-) diff --git a/configs/surface-6.19.config b/configs/surface-6.19.config index 6441f1b667..1c11f9c866 100644 --- a/configs/surface-6.19.config +++ b/configs/surface-6.19.config @@ -69,12 +69,6 @@ CONFIG_VIDEO_OV8865=m ## CONFIG_APDS9960=m -## -## Build-in UFS support (required for some Surface Go devices) -## -CONFIG_SCSI_UFSHCD=m -CONFIG_SCSI_UFSHCD_PCI=m - ## ## Other Drivers ## diff --git a/pkg/fedora/kernel-surface/configs/fedora.config b/pkg/fedora/kernel-surface/configs/fedora.config index f9b5fdc3f7..6446332eb0 100644 --- a/pkg/fedora/kernel-surface/configs/fedora.config +++ b/pkg/fedora/kernel-surface/configs/fedora.config @@ -13,74 +13,3 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y ## # CONFIG_EFI_DXE_MEM_ATTRIBUTES is not set -## -## UFS pulls in DEVFREQ and NLS modules. Fedora's packaging system complains -## and aborts if any options aren't specified, so specify them explicitly here. -## -CONFIG_DEVFREQ_THERMAL=y -CONFIG_SCSI_UFS_BSG=y -CONFIG_SCSI_UFS_CRYPTO=y -# CONFIG_SCSI_UFS_FAULT_INJECTION is not set -# CONFIG_SCSI_UFS_DWC_TC_PCI is not set -# CONFIG_SCSI_UFS_TI_J721E is not set -# CONFIG_SCSI_UFS_CDNS_PLATFORM is not set -# CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set -# CONFIG_SCSI_UFS_QCOM is not set -# CONFIG_SCSI_UFS_HISI is not set -CONFIG_SCSI_UFSHCD=m -CONFIG_SCSI_UFSHCD_PLATFORM=m -CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y -CONFIG_DEVFREQ_GOV_PERFORMANCE=y -CONFIG_DEVFREQ_GOV_POWERSAVE=y -CONFIG_DEVFREQ_GOV_USERSPACE=y -CONFIG_DEVFREQ_GOV_PASSIVE=y -CONFIG_PM_DEVFREQ=y -CONFIG_PM_DEVFREQ_EVENT=y -CONFIG_NLS=y -CONFIG_NLS_CODEPAGE_737=y -CONFIG_NLS_CODEPAGE_775=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_CODEPAGE_852=y -CONFIG_NLS_CODEPAGE_855=y -CONFIG_NLS_CODEPAGE_857=y -CONFIG_NLS_CODEPAGE_860=y -CONFIG_NLS_CODEPAGE_861=y -CONFIG_NLS_CODEPAGE_862=y -CONFIG_NLS_CODEPAGE_863=y -CONFIG_NLS_CODEPAGE_864=y -CONFIG_NLS_CODEPAGE_865=y -CONFIG_NLS_CODEPAGE_866=y -CONFIG_NLS_CODEPAGE_869=y -CONFIG_NLS_CODEPAGE_936=y -CONFIG_NLS_CODEPAGE_950=y -CONFIG_NLS_CODEPAGE_932=y -CONFIG_NLS_CODEPAGE_949=y -CONFIG_NLS_CODEPAGE_874=y -CONFIG_NLS_ISO8859_8=y -CONFIG_NLS_CODEPAGE_1250=y -CONFIG_NLS_CODEPAGE_1251=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_2=y -CONFIG_NLS_ISO8859_3=y -CONFIG_NLS_ISO8859_4=y -CONFIG_NLS_ISO8859_5=y -CONFIG_NLS_ISO8859_6=y -CONFIG_NLS_ISO8859_7=y -CONFIG_NLS_ISO8859_9=y -CONFIG_NLS_ISO8859_13=y -CONFIG_NLS_ISO8859_14=y -CONFIG_NLS_ISO8859_15=y -CONFIG_NLS_KOI8_R=y -CONFIG_NLS_KOI8_U=y -CONFIG_NLS_MAC_ROMAN=y -CONFIG_NLS_MAC_CELTIC=y -CONFIG_NLS_MAC_CENTEURO=y -CONFIG_NLS_MAC_CROATIAN=y -CONFIG_NLS_MAC_CYRILLIC=y -CONFIG_NLS_MAC_GAELIC=y -CONFIG_NLS_MAC_GREEK=y -CONFIG_NLS_MAC_ICELAND=y -CONFIG_NLS_MAC_INUIT=y -CONFIG_NLS_MAC_ROMANIAN=y -CONFIG_NLS_MAC_TURKISH=y -CONFIG_NLS_UTF8=y From 4cbbe2ed574d7ec3384c611fba32fad3bf7b6ee8 Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Sat, 9 May 2026 04:07:52 -0400 Subject: [PATCH 235/236] patches: Fix dirty frag vulnerability (#2117) Fixes: https://github.com/linux-surface/linux-surface/issues/2116 --- ...in-place-decrypt-on-shared-skb-frags.patch | 103 ++++++++++ ...ential-UAF-after-skb_unshare-failure.patch | 185 ++++++++++++++++++ ...input_call_event-to-only-unshare-DAT.patch | 44 +++++ ...-wrong-skb-when-comparing-queued-RES.patch | 72 +++++++ ...le-RESPONSE-during-service-challenge.patch | 79 ++++++++ ...evel-packet-handling-to-unshare-RESP.patch | 79 ++++++++ ...ix-re-decryption-of-RESPONSE-packets.patch | 76 +++++++ ...re-DATA-RESPONSE-packets-when-paged-.patch | 54 +++++ ...in-place-decrypt-on-shared-skb-frags.patch | 103 ++++++++++ ...ential-UAF-after-skb_unshare-failure.patch | 185 ++++++++++++++++++ ...input_call_event-to-only-unshare-DAT.patch | 44 +++++ ...-wrong-skb-when-comparing-queued-RES.patch | 72 +++++++ ...le-RESPONSE-during-service-challenge.patch | 79 ++++++++ ...evel-packet-handling-to-unshare-RESP.patch | 79 ++++++++ ...ix-re-decryption-of-RESPONSE-packets.patch | 76 +++++++ ...re-DATA-RESPONSE-packets-when-paged-.patch | 55 ++++++ ...in-place-decrypt-on-shared-skb-frags.patch | 1 + ...ential-UAF-after-skb_unshare-failure.patch | 1 + ...input_call_event-to-only-unshare-DAT.patch | 1 + ...-wrong-skb-when-comparing-queued-RES.patch | 1 + ...le-RESPONSE-during-service-challenge.patch | 1 + ...evel-packet-handling-to-unshare-RESP.patch | 1 + ...ix-re-decryption-of-RESPONSE-packets.patch | 1 + ...re-DATA-RESPONSE-packets-when-paged-.patch | 1 + pkg/arch/kernel/PKGBUILD | 20 +- pkg/debian/kernel/version.conf | 2 +- .../kernel-surface/build-linux-surface.py | 2 +- 27 files changed, 1413 insertions(+), 4 deletions(-) create mode 100644 patches/6.18/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch create mode 100644 patches/6.18/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch create mode 100644 patches/6.18/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch create mode 100644 patches/6.18/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch create mode 100644 patches/6.18/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch create mode 100644 patches/6.18/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch create mode 100644 patches/6.18/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch create mode 100644 patches/6.18/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch create mode 100644 patches/6.19/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch create mode 100644 patches/6.19/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch create mode 100644 patches/6.19/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch create mode 100644 patches/6.19/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch create mode 100644 patches/6.19/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch create mode 100644 patches/6.19/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch create mode 100644 patches/6.19/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch create mode 100644 patches/6.19/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch create mode 120000 pkg/arch/kernel/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch create mode 120000 pkg/arch/kernel/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch create mode 120000 pkg/arch/kernel/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch create mode 120000 pkg/arch/kernel/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch create mode 120000 pkg/arch/kernel/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch create mode 120000 pkg/arch/kernel/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch create mode 120000 pkg/arch/kernel/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch create mode 120000 pkg/arch/kernel/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch diff --git a/patches/6.18/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch b/patches/6.18/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch new file mode 100644 index 0000000000..332d80fead --- /dev/null +++ b/patches/6.18/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch @@ -0,0 +1,103 @@ +From 8c4594b14b091d851114f02ac33235ee06a2b29e Mon Sep 17 00:00:00 2001 +From: Kuan-Ting Chen +Date: Mon, 4 May 2026 23:27:12 +0800 +Subject: [PATCH 1/8] xfrm: esp: avoid in-place decrypt on shared skb frags + +MSG_SPLICE_PAGES can attach pages from a pipe directly to an skb. TCP +marks such skbs with SKBFL_SHARED_FRAG after skb_splice_from_iter(), +so later paths that may modify packet data can first make a private +copy. The IPv4/IPv6 datagram append paths did not set this flag when +splicing pages into UDP skbs. + +That leaves an ESP-in-UDP packet made from shared pipe pages looking +like an ordinary uncloned nonlinear skb. ESP input then takes the no-COW +fast path for uncloned skbs without a frag_list and decrypts in place +over data that is not owned privately by the skb. + +Mark IPv4/IPv6 datagram splice frags with SKBFL_SHARED_FRAG, matching +TCP. Also make ESP input fall back to skb_cow_data() when the flag is +present, so ESP does not decrypt externally backed frags in place. +Private nonlinear skb frags still use the existing fast path. + +This intentionally does not change ESP output. In esp_output_head(), +the path that appends the ESP trailer to existing skb tailroom without +calling skb_cow_data() is not reachable for nonlinear skbs: +skb_tailroom() returns zero when skb->data_len is nonzero, while ESP +tailen is positive. Thus ESP output will either use the separate +destination-frag path or fall back to skb_cow_data(). + +Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") +Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") +Fixes: 7da0dde68486 ("ip, udp: Support MSG_SPLICE_PAGES") +Fixes: 6d8192bd69bb ("ip6, udp6: Support MSG_SPLICE_PAGES") +Reported-by: Hyunwoo Kim +Reported-by: Kuan-Ting Chen +Tested-by: Hyunwoo Kim +Cc: stable@vger.kernel.org +Signed-off-by: Kuan-Ting Chen +Signed-off-by: Steffen Klassert +(cherry picked from commit f4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4) +--- + net/ipv4/esp4.c | 3 ++- + net/ipv4/ip_output.c | 2 ++ + net/ipv6/esp6.c | 3 ++- + net/ipv6/ip6_output.c | 2 ++ + 4 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c +index 2c922afadb8f..ba3743ea78cb 100644 +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -870,7 +870,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) + nfrags = 1; + + goto skip_cow; +- } else if (!skb_has_frag_list(skb)) { ++ } else if (!skb_has_frag_list(skb) && ++ !skb_has_shared_frag(skb)) { + nfrags = skb_shinfo(skb)->nr_frags; + nfrags++; + +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index ff11d3a85a36..7c005263262f 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -1233,6 +1233,8 @@ static int __ip_append_data(struct sock *sk, + if (err < 0) + goto error; + copy = err; ++ if (!(flags & MSG_NO_SHARED_FRAGS)) ++ skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; + wmem_alloc_delta += copy; + } else if (!zc) { + int i = skb_shinfo(skb)->nr_frags; +diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c +index e75da98f5283..116582d6985f 100644 +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -912,7 +912,8 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) + nfrags = 1; + + goto skip_cow; +- } else if (!skb_has_frag_list(skb)) { ++ } else if (!skb_has_frag_list(skb) && ++ !skb_has_shared_frag(skb)) { + nfrags = skb_shinfo(skb)->nr_frags; + nfrags++; + +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index f904739e99b9..f5ca0267e770 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1777,6 +1777,8 @@ static int __ip6_append_data(struct sock *sk, + if (err < 0) + goto error; + copy = err; ++ if (!(flags & MSG_NO_SHARED_FRAGS)) ++ skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; + wmem_alloc_delta += copy; + } else if (!zc) { + int i = skb_shinfo(skb)->nr_frags; +-- +2.53.0 + diff --git a/patches/6.18/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch b/patches/6.18/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch new file mode 100644 index 0000000000..b8a2b3bdfa --- /dev/null +++ b/patches/6.18/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch @@ -0,0 +1,185 @@ +From c863821f44c64505df5851090919237a089bcf65 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Wed, 22 Apr 2026 17:14:32 +0100 +Subject: [PATCH 2/8] rxrpc: Fix potential UAF after skb_unshare() failure + +If skb_unshare() fails to unshare a packet due to allocation failure in +rxrpc_input_packet(), the skb pointer in the parent (rxrpc_io_thread()) +will be NULL'd out. This will likely cause the call to +trace_rxrpc_rx_done() to oops. + +Fix this by moving the unsharing down to where rxrpc_input_call_event() +calls rxrpc_input_call_packet(). There are a number of places prior to +that where we ignore DATA packets for a variety of reasons (such as the +call already being complete) for which an unshare is then avoided. + +And with that, rxrpc_input_packet() doesn't need to take a pointer to the +pointer to the packet, so change that to just a pointer. + +Fixes: 2d1faf7a0ca3 ("rxrpc: Simplify skbuff accounting in receive path") +Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260422161438.2593376-4-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 1f2740150f904bfa60e4bad74d65add3ccb5e7f8) +--- + include/trace/events/rxrpc.h | 4 ++-- + net/rxrpc/ar-internal.h | 1 - + net/rxrpc/call_event.c | 19 ++++++++++++++++++- + net/rxrpc/io_thread.c | 24 ++---------------------- + net/rxrpc/skbuff.c | 9 --------- + 5 files changed, 22 insertions(+), 35 deletions(-) + +diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h +index 869f97c9bf73..8a338f370de9 100644 +--- a/include/trace/events/rxrpc.h ++++ b/include/trace/events/rxrpc.h +@@ -161,8 +161,6 @@ + E_(rxrpc_call_poke_timer_now, "Timer-now") + + #define rxrpc_skb_traces \ +- EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \ +- EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \ + EM(rxrpc_skb_get_call_rx, "GET call-rx ") \ + EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \ + EM(rxrpc_skb_get_conn_work, "GET conn-work") \ +@@ -188,6 +186,7 @@ + EM(rxrpc_skb_put_purge, "PUT purge ") \ + EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \ + EM(rxrpc_skb_put_response, "PUT response ") \ ++ EM(rxrpc_skb_put_response_copy, "PUT resp-cpy ") \ + EM(rxrpc_skb_put_rotate, "PUT rotate ") \ + EM(rxrpc_skb_put_unknown, "PUT unknown ") \ + EM(rxrpc_skb_see_conn_work, "SEE conn-work") \ +@@ -196,6 +195,7 @@ + EM(rxrpc_skb_see_recvmsg_oob, "SEE recvm-oob") \ + EM(rxrpc_skb_see_reject, "SEE reject ") \ + EM(rxrpc_skb_see_rotate, "SEE rotate ") \ ++ EM(rxrpc_skb_see_unshare_nomem, "SEE unshar-nm") \ + E_(rxrpc_skb_see_version, "SEE version ") + + #define rxrpc_local_traces \ +diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h +index 36d6ca0d1089..41b3fb28c59c 100644 +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -1486,7 +1486,6 @@ int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int); + void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *); + void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace); + void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace); +-void rxrpc_eaten_skb(struct sk_buff *, enum rxrpc_skb_trace); + void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace); + void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace); + void rxrpc_purge_queue(struct sk_buff_head *); +diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c +index fec59d9338b9..cc8f9dfa44e8 100644 +--- a/net/rxrpc/call_event.c ++++ b/net/rxrpc/call_event.c +@@ -332,7 +332,24 @@ bool rxrpc_input_call_event(struct rxrpc_call *call) + + saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK; + +- rxrpc_input_call_packet(call, skb); ++ if (sp->hdr.securityIndex != 0 && ++ skb_cloned(skb)) { ++ /* Unshare the packet so that it can be ++ * modified by in-place decryption. ++ */ ++ struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); ++ ++ if (nskb) { ++ rxrpc_new_skb(nskb, rxrpc_skb_new_unshared); ++ rxrpc_input_call_packet(call, nskb); ++ rxrpc_free_skb(nskb, rxrpc_skb_put_call_rx); ++ } else { ++ /* OOM - Drop the packet. */ ++ rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem); ++ } ++ } else { ++ rxrpc_input_call_packet(call, skb); ++ } + rxrpc_free_skb(skb, rxrpc_skb_put_call_rx); + did_receive = true; + } +diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c +index e939ecf417c4..6ff30afbc085 100644 +--- a/net/rxrpc/io_thread.c ++++ b/net/rxrpc/io_thread.c +@@ -192,13 +192,12 @@ static bool rxrpc_extract_abort(struct sk_buff *skb) + /* + * Process packets received on the local endpoint + */ +-static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) ++static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff *skb) + { + struct rxrpc_connection *conn; + struct sockaddr_rxrpc peer_srx; + struct rxrpc_skb_priv *sp; + struct rxrpc_peer *peer = NULL; +- struct sk_buff *skb = *_skb; + bool ret = false; + + skb_pull(skb, sizeof(struct udphdr)); +@@ -244,25 +243,6 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) + return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call); + if (sp->hdr.seq == 0) + return rxrpc_bad_message(skb, rxrpc_badmsg_zero_seq); +- +- /* Unshare the packet so that it can be modified for in-place +- * decryption. +- */ +- if (sp->hdr.securityIndex != 0) { +- skb = skb_unshare(skb, GFP_ATOMIC); +- if (!skb) { +- rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem); +- *_skb = NULL; +- return just_discard; +- } +- +- if (skb != *_skb) { +- rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare); +- *_skb = skb; +- rxrpc_new_skb(skb, rxrpc_skb_new_unshared); +- sp = rxrpc_skb(skb); +- } +- } + break; + + case RXRPC_PACKET_TYPE_CHALLENGE: +@@ -493,7 +473,7 @@ int rxrpc_io_thread(void *data) + switch (skb->mark) { + case RXRPC_SKB_MARK_PACKET: + skb->priority = 0; +- if (!rxrpc_input_packet(local, &skb)) ++ if (!rxrpc_input_packet(local, skb)) + rxrpc_reject_packet(local, skb); + trace_rxrpc_rx_done(skb->mark, skb->priority); + rxrpc_free_skb(skb, rxrpc_skb_put_input); +diff --git a/net/rxrpc/skbuff.c b/net/rxrpc/skbuff.c +index 3bcd6ee80396..e2169d1a14b5 100644 +--- a/net/rxrpc/skbuff.c ++++ b/net/rxrpc/skbuff.c +@@ -46,15 +46,6 @@ void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace why) + skb_get(skb); + } + +-/* +- * Note the dropping of a ref on a socket buffer by the core. +- */ +-void rxrpc_eaten_skb(struct sk_buff *skb, enum rxrpc_skb_trace why) +-{ +- int n = atomic_inc_return(&rxrpc_n_rx_skbs); +- trace_rxrpc_skb(skb, 0, n, why); +-} +- + /* + * Note the destruction of a socket buffer. + */ +-- +2.53.0 + diff --git a/patches/6.18/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch b/patches/6.18/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch new file mode 100644 index 0000000000..2ba346ed66 --- /dev/null +++ b/patches/6.18/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch @@ -0,0 +1,44 @@ +From 53e3b2bcd7d1a1fb428d0883a05b54bb0d366b82 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Thu, 23 Apr 2026 21:09:06 +0100 +Subject: [PATCH 3/8] rxrpc: Fix rxrpc_input_call_event() to only unshare DATA + packets + +Fix rxrpc_input_call_event() to only unshare DATA packets and not ACK, +ABORT, etc.. + +And with that, rxrpc_input_packet() doesn't need to take a pointer to the +pointer to the packet, so change that to just a pointer. + +Fixes: 1f2740150f90 ("rxrpc: Fix potential UAF after skb_unshare() failure") +Closes: https://sashiko.dev/#/patchset/20260422161438.2593376-4-dhowells@redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260423200909.3049438-2-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 55b2984c96c37f909bbfe8851f13152693951382) +--- + net/rxrpc/call_event.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c +index cc8f9dfa44e8..fdd683261226 100644 +--- a/net/rxrpc/call_event.c ++++ b/net/rxrpc/call_event.c +@@ -332,7 +332,8 @@ bool rxrpc_input_call_event(struct rxrpc_call *call) + + saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK; + +- if (sp->hdr.securityIndex != 0 && ++ if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA && ++ sp->hdr.securityIndex != 0 && + skb_cloned(skb)) { + /* Unshare the packet so that it can be + * modified by in-place decryption. +-- +2.53.0 + diff --git a/patches/6.18/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch b/patches/6.18/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch new file mode 100644 index 0000000000..188b816c27 --- /dev/null +++ b/patches/6.18/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch @@ -0,0 +1,72 @@ +From 94973b24d4136293be23603a914967747da0c6a7 Mon Sep 17 00:00:00 2001 +From: Alok Tiwari +Date: Wed, 8 Apr 2026 13:12:34 +0100 +Subject: [PATCH 4/8] rxrpc: Fix use of wrong skb when comparing queued RESP + challenge serial + +In rxrpc_post_response(), the code should be comparing the challenge serial +number from the cached response before deciding to switch to a newer +response, but looks at the newer packet private data instead, rendering the +comparison always false. + +Fix this by switching to look at the older packet. + +Fix further[1] to substitute the new packet in place of the old one if +newer and also to release whichever we don't use. + +Fixes: 5800b1cf3fd8 ("rxrpc: Allow CHALLENGEs to the passed to the app for a RESPONSE") +Signed-off-by: Alok Tiwari +Signed-off-by: David Howells +Reviewed-by: Jeffrey Altman +cc: Marc Dionne +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com [1] +Link: https://patch.msgid.link/20260408121252.2249051-7-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit b33f5741bb187db8ff32e8f5b96def77cc94dfca) +--- + include/trace/events/rxrpc.h | 1 + + net/rxrpc/conn_event.c | 5 +++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h +index 8a338f370de9..94f804ec8831 100644 +--- a/include/trace/events/rxrpc.h ++++ b/include/trace/events/rxrpc.h +@@ -183,6 +183,7 @@ + EM(rxrpc_skb_put_input, "PUT input ") \ + EM(rxrpc_skb_put_jumbo_subpacket, "PUT jumbo-sub") \ + EM(rxrpc_skb_put_oob, "PUT oob ") \ ++ EM(rxrpc_skb_put_old_response, "PUT old-resp ") \ + EM(rxrpc_skb_put_purge, "PUT purge ") \ + EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \ + EM(rxrpc_skb_put_response, "PUT response ") \ +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index 98ad9b51ca2c..c50cbfc5a313 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -557,11 +557,11 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb) + spin_lock_irq(&local->lock); + old = conn->tx_response; + if (old) { +- struct rxrpc_skb_priv *osp = rxrpc_skb(skb); ++ struct rxrpc_skb_priv *osp = rxrpc_skb(old); + + /* Always go with the response to the most recent challenge. */ + if (after(sp->resp.challenge_serial, osp->resp.challenge_serial)) +- conn->tx_response = old; ++ conn->tx_response = skb; + else + old = skb; + } else { +@@ -569,4 +569,5 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb) + } + spin_unlock_irq(&local->lock); + rxrpc_poke_conn(conn, rxrpc_conn_get_poke_response); ++ rxrpc_free_skb(old, rxrpc_skb_put_old_response); + } +-- +2.53.0 + diff --git a/patches/6.18/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch b/patches/6.18/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch new file mode 100644 index 0000000000..b524f4eafe --- /dev/null +++ b/patches/6.18/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch @@ -0,0 +1,79 @@ +From 662e6d8b63299d3c0d2a57bdf73e39210ea8a424 Mon Sep 17 00:00:00 2001 +From: Wang Jie +Date: Wed, 8 Apr 2026 13:12:48 +0100 +Subject: [PATCH 5/8] rxrpc: only handle RESPONSE during service challenge + +Only process RESPONSE packets while the service connection is still in +RXRPC_CONN_SERVICE_CHALLENGING. Check that state under state_lock before +running response verification and security initialization, then use a local +secured flag to decide whether to queue the secured-connection work after +the state transition. This keeps duplicate or late RESPONSE packets from +re-running the setup path and removes the unlocked post-transition state +test. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Jie Wang +Signed-off-by: Yang Yang +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260408121252.2249051-21-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit c43ffdcfdbb5567b1f143556df8a04b4eeea041c) +--- + net/rxrpc/conn_event.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index c50cbfc5a313..9a41ec708aeb 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -247,6 +247,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, + struct sk_buff *skb) + { + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); ++ bool secured = false; + int ret; + + if (conn->state == RXRPC_CONN_ABORTED) +@@ -262,6 +263,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, + return ret; + + case RXRPC_PACKET_TYPE_RESPONSE: ++ spin_lock_irq(&conn->state_lock); ++ if (conn->state != RXRPC_CONN_SERVICE_CHALLENGING) { ++ spin_unlock_irq(&conn->state_lock); ++ return 0; ++ } ++ spin_unlock_irq(&conn->state_lock); ++ + ret = conn->security->verify_response(conn, skb); + if (ret < 0) + return ret; +@@ -272,11 +280,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, + return ret; + + spin_lock_irq(&conn->state_lock); +- if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) ++ if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) { + conn->state = RXRPC_CONN_SERVICE; ++ secured = true; ++ } + spin_unlock_irq(&conn->state_lock); + +- if (conn->state == RXRPC_CONN_SERVICE) { ++ if (secured) { + /* Offload call state flipping to the I/O thread. As + * we've already received the packet, put it on the + * front of the queue. +-- +2.53.0 + diff --git a/patches/6.18/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch b/patches/6.18/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch new file mode 100644 index 0000000000..f779b500d9 --- /dev/null +++ b/patches/6.18/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch @@ -0,0 +1,79 @@ +From a7f61c028f5fda7e1da489288a36d632a61ace5a Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Wed, 22 Apr 2026 17:14:33 +0100 +Subject: [PATCH 6/8] rxrpc: Fix conn-level packet handling to unshare RESPONSE + packets + +The security operations that verify the RESPONSE packets decrypt bits of it +in place - however, the sk_buff may be shared with a packet sniffer, which +would lead to the sniffer seeing an apparently corrupt packet (actually +decrypted). + +Fix this by handing a copy of the packet off to the specific security +handler if the packet was cloned. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260422161438.2593376-5-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 24481a7f573305706054c59e275371f8d0fe919f) +--- + net/rxrpc/conn_event.c | 29 ++++++++++++++++++++++++++++- + 1 file changed, 28 insertions(+), 1 deletion(-) + +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index 9a41ec708aeb..aee977291d90 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -240,6 +240,33 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call) + rxrpc_notify_socket(call); + } + ++static int rxrpc_verify_response(struct rxrpc_connection *conn, ++ struct sk_buff *skb) ++{ ++ int ret; ++ ++ if (skb_cloned(skb)) { ++ /* Copy the packet if shared so that we can do in-place ++ * decryption. ++ */ ++ struct sk_buff *nskb = skb_copy(skb, GFP_NOFS); ++ ++ if (nskb) { ++ rxrpc_new_skb(nskb, rxrpc_skb_new_unshared); ++ ret = conn->security->verify_response(conn, nskb); ++ rxrpc_free_skb(nskb, rxrpc_skb_put_response_copy); ++ } else { ++ /* OOM - Drop the packet. */ ++ rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem); ++ ret = -ENOMEM; ++ } ++ } else { ++ ret = conn->security->verify_response(conn, skb); ++ } ++ ++ return ret; ++} ++ + /* + * connection-level Rx packet processor + */ +@@ -270,7 +297,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, + } + spin_unlock_irq(&conn->state_lock); + +- ret = conn->security->verify_response(conn, skb); ++ ret = rxrpc_verify_response(conn, skb); + if (ret < 0) + return ret; + +-- +2.53.0 + diff --git a/patches/6.18/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch b/patches/6.18/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch new file mode 100644 index 0000000000..26b74e266b --- /dev/null +++ b/patches/6.18/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch @@ -0,0 +1,76 @@ +From 98be347c5f2564c13fc8def0ecb2ed0cca54a11a Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Thu, 23 Apr 2026 21:09:07 +0100 +Subject: [PATCH 7/8] rxrpc: Fix re-decryption of RESPONSE packets + +If a RESPONSE packet gets a temporary failure during processing, it may end +up in a partially decrypted state - and then get requeued for a retry. + +Fix this by just discarding the packet; we will send another CHALLENGE +packet and thereby elicit a further response. Similarly, discard an +incoming CHALLENGE packet if we get an error whilst generating a RESPONSE; +the server will send another CHALLENGE. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Closes: https://sashiko.dev/#/patchset/20260422161438.2593376-4-dhowells@redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260423200909.3049438-3-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 0422e7a4883f25101903f3e8105c0808aa5f4ce9) +--- + include/trace/events/rxrpc.h | 1 - + net/rxrpc/conn_event.c | 14 ++------------ + 2 files changed, 2 insertions(+), 13 deletions(-) + +diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h +index 94f804ec8831..eb8150afd6df 100644 +--- a/include/trace/events/rxrpc.h ++++ b/include/trace/events/rxrpc.h +@@ -284,7 +284,6 @@ + EM(rxrpc_conn_put_unidle, "PUT unidle ") \ + EM(rxrpc_conn_put_work, "PUT work ") \ + EM(rxrpc_conn_queue_challenge, "QUE chall ") \ +- EM(rxrpc_conn_queue_retry_work, "QUE retry-wk") \ + EM(rxrpc_conn_queue_rx_work, "QUE rx-work ") \ + EM(rxrpc_conn_see_new_service_conn, "SEE new-svc ") \ + EM(rxrpc_conn_see_reap_service, "SEE reap-svc") \ +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index aee977291d90..a2130d25aaa9 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -389,7 +389,6 @@ void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force) + static void rxrpc_do_process_connection(struct rxrpc_connection *conn) + { + struct sk_buff *skb; +- int ret; + + if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events)) + rxrpc_secure_connection(conn); +@@ -398,17 +397,8 @@ static void rxrpc_do_process_connection(struct rxrpc_connection *conn) + * connection that each one has when we've finished with it */ + while ((skb = skb_dequeue(&conn->rx_queue))) { + rxrpc_see_skb(skb, rxrpc_skb_see_conn_work); +- ret = rxrpc_process_event(conn, skb); +- switch (ret) { +- case -ENOMEM: +- case -EAGAIN: +- skb_queue_head(&conn->rx_queue, skb); +- rxrpc_queue_conn(conn, rxrpc_conn_queue_retry_work); +- break; +- default: +- rxrpc_free_skb(skb, rxrpc_skb_put_conn_work); +- break; +- } ++ rxrpc_process_event(conn, skb); ++ rxrpc_free_skb(skb, rxrpc_skb_put_conn_work); + } + } + +-- +2.53.0 + diff --git a/patches/6.18/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch b/patches/6.18/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch new file mode 100644 index 0000000000..9338f061ed --- /dev/null +++ b/patches/6.18/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch @@ -0,0 +1,54 @@ +From 606cb2021745a1206f43a24b6c795c187e01df6f Mon Sep 17 00:00:00 2001 +From: Hyunwoo Kim +Date: Fri, 8 May 2026 15:42:28 +0900 +Subject: [PATCH 8/8] rxrpc: Also unshare DATA/RESPONSE packets when paged + frags are present + +The DATA-packet handler in rxrpc_input_call_event() and the RESPONSE +handler in rxrpc_verify_response() copy the skb to a linear one before +calling into the security ops only when skb_cloned() is true. An skb +that is not cloned but still carries paged fragments (skb->data_len != 0) +falls through to the in-place decryption path, which binds the frag +pages directly into the AEAD/skcipher SGL via skb_to_sgvec(). + +Extend the gate so that any skb with non-linear data is also copied, +ensuring the security handler always operates on a fully linear skb. +The OOM/trace handling already in place is reused. + +Fixes: d0d5c0cd1e71 ("rxrpc: Use skb_unshare() rather than skb_cow_data()") +Cc: stable@vger.kernel.org +Signed-off-by: Hyunwoo Kim +--- + net/rxrpc/call_event.c | 2 +- + net/rxrpc/conn_event.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c +index fdd683261226..a6ad5ff6ec5f 100644 +--- a/net/rxrpc/call_event.c ++++ b/net/rxrpc/call_event.c +@@ -334,7 +334,7 @@ bool rxrpc_input_call_event(struct rxrpc_call *call) + + if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA && + sp->hdr.securityIndex != 0 && +- skb_cloned(skb)) { ++ (skb_cloned(skb) || skb_is_nonlinear(skb))) { + /* Unshare the packet so that it can be + * modified by in-place decryption. + */ +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index a2130d25aaa9..632cbeff1f5d 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -245,7 +245,7 @@ static int rxrpc_verify_response(struct rxrpc_connection *conn, + { + int ret; + +- if (skb_cloned(skb)) { ++ if (skb_cloned(skb) || skb_is_nonlinear(skb)) { + /* Copy the packet if shared so that we can do in-place + * decryption. + */ +-- +2.53.0 + diff --git a/patches/6.19/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch b/patches/6.19/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch new file mode 100644 index 0000000000..332d80fead --- /dev/null +++ b/patches/6.19/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch @@ -0,0 +1,103 @@ +From 8c4594b14b091d851114f02ac33235ee06a2b29e Mon Sep 17 00:00:00 2001 +From: Kuan-Ting Chen +Date: Mon, 4 May 2026 23:27:12 +0800 +Subject: [PATCH 1/8] xfrm: esp: avoid in-place decrypt on shared skb frags + +MSG_SPLICE_PAGES can attach pages from a pipe directly to an skb. TCP +marks such skbs with SKBFL_SHARED_FRAG after skb_splice_from_iter(), +so later paths that may modify packet data can first make a private +copy. The IPv4/IPv6 datagram append paths did not set this flag when +splicing pages into UDP skbs. + +That leaves an ESP-in-UDP packet made from shared pipe pages looking +like an ordinary uncloned nonlinear skb. ESP input then takes the no-COW +fast path for uncloned skbs without a frag_list and decrypts in place +over data that is not owned privately by the skb. + +Mark IPv4/IPv6 datagram splice frags with SKBFL_SHARED_FRAG, matching +TCP. Also make ESP input fall back to skb_cow_data() when the flag is +present, so ESP does not decrypt externally backed frags in place. +Private nonlinear skb frags still use the existing fast path. + +This intentionally does not change ESP output. In esp_output_head(), +the path that appends the ESP trailer to existing skb tailroom without +calling skb_cow_data() is not reachable for nonlinear skbs: +skb_tailroom() returns zero when skb->data_len is nonzero, while ESP +tailen is positive. Thus ESP output will either use the separate +destination-frag path or fall back to skb_cow_data(). + +Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") +Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") +Fixes: 7da0dde68486 ("ip, udp: Support MSG_SPLICE_PAGES") +Fixes: 6d8192bd69bb ("ip6, udp6: Support MSG_SPLICE_PAGES") +Reported-by: Hyunwoo Kim +Reported-by: Kuan-Ting Chen +Tested-by: Hyunwoo Kim +Cc: stable@vger.kernel.org +Signed-off-by: Kuan-Ting Chen +Signed-off-by: Steffen Klassert +(cherry picked from commit f4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4) +--- + net/ipv4/esp4.c | 3 ++- + net/ipv4/ip_output.c | 2 ++ + net/ipv6/esp6.c | 3 ++- + net/ipv6/ip6_output.c | 2 ++ + 4 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c +index 2c922afadb8f..ba3743ea78cb 100644 +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -870,7 +870,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) + nfrags = 1; + + goto skip_cow; +- } else if (!skb_has_frag_list(skb)) { ++ } else if (!skb_has_frag_list(skb) && ++ !skb_has_shared_frag(skb)) { + nfrags = skb_shinfo(skb)->nr_frags; + nfrags++; + +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index ff11d3a85a36..7c005263262f 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -1233,6 +1233,8 @@ static int __ip_append_data(struct sock *sk, + if (err < 0) + goto error; + copy = err; ++ if (!(flags & MSG_NO_SHARED_FRAGS)) ++ skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; + wmem_alloc_delta += copy; + } else if (!zc) { + int i = skb_shinfo(skb)->nr_frags; +diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c +index e75da98f5283..116582d6985f 100644 +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -912,7 +912,8 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) + nfrags = 1; + + goto skip_cow; +- } else if (!skb_has_frag_list(skb)) { ++ } else if (!skb_has_frag_list(skb) && ++ !skb_has_shared_frag(skb)) { + nfrags = skb_shinfo(skb)->nr_frags; + nfrags++; + +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index f904739e99b9..f5ca0267e770 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1777,6 +1777,8 @@ static int __ip6_append_data(struct sock *sk, + if (err < 0) + goto error; + copy = err; ++ if (!(flags & MSG_NO_SHARED_FRAGS)) ++ skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; + wmem_alloc_delta += copy; + } else if (!zc) { + int i = skb_shinfo(skb)->nr_frags; +-- +2.53.0 + diff --git a/patches/6.19/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch b/patches/6.19/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch new file mode 100644 index 0000000000..b8a2b3bdfa --- /dev/null +++ b/patches/6.19/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch @@ -0,0 +1,185 @@ +From c863821f44c64505df5851090919237a089bcf65 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Wed, 22 Apr 2026 17:14:32 +0100 +Subject: [PATCH 2/8] rxrpc: Fix potential UAF after skb_unshare() failure + +If skb_unshare() fails to unshare a packet due to allocation failure in +rxrpc_input_packet(), the skb pointer in the parent (rxrpc_io_thread()) +will be NULL'd out. This will likely cause the call to +trace_rxrpc_rx_done() to oops. + +Fix this by moving the unsharing down to where rxrpc_input_call_event() +calls rxrpc_input_call_packet(). There are a number of places prior to +that where we ignore DATA packets for a variety of reasons (such as the +call already being complete) for which an unshare is then avoided. + +And with that, rxrpc_input_packet() doesn't need to take a pointer to the +pointer to the packet, so change that to just a pointer. + +Fixes: 2d1faf7a0ca3 ("rxrpc: Simplify skbuff accounting in receive path") +Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260422161438.2593376-4-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 1f2740150f904bfa60e4bad74d65add3ccb5e7f8) +--- + include/trace/events/rxrpc.h | 4 ++-- + net/rxrpc/ar-internal.h | 1 - + net/rxrpc/call_event.c | 19 ++++++++++++++++++- + net/rxrpc/io_thread.c | 24 ++---------------------- + net/rxrpc/skbuff.c | 9 --------- + 5 files changed, 22 insertions(+), 35 deletions(-) + +diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h +index 869f97c9bf73..8a338f370de9 100644 +--- a/include/trace/events/rxrpc.h ++++ b/include/trace/events/rxrpc.h +@@ -161,8 +161,6 @@ + E_(rxrpc_call_poke_timer_now, "Timer-now") + + #define rxrpc_skb_traces \ +- EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \ +- EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \ + EM(rxrpc_skb_get_call_rx, "GET call-rx ") \ + EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \ + EM(rxrpc_skb_get_conn_work, "GET conn-work") \ +@@ -188,6 +186,7 @@ + EM(rxrpc_skb_put_purge, "PUT purge ") \ + EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \ + EM(rxrpc_skb_put_response, "PUT response ") \ ++ EM(rxrpc_skb_put_response_copy, "PUT resp-cpy ") \ + EM(rxrpc_skb_put_rotate, "PUT rotate ") \ + EM(rxrpc_skb_put_unknown, "PUT unknown ") \ + EM(rxrpc_skb_see_conn_work, "SEE conn-work") \ +@@ -196,6 +195,7 @@ + EM(rxrpc_skb_see_recvmsg_oob, "SEE recvm-oob") \ + EM(rxrpc_skb_see_reject, "SEE reject ") \ + EM(rxrpc_skb_see_rotate, "SEE rotate ") \ ++ EM(rxrpc_skb_see_unshare_nomem, "SEE unshar-nm") \ + E_(rxrpc_skb_see_version, "SEE version ") + + #define rxrpc_local_traces \ +diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h +index 36d6ca0d1089..41b3fb28c59c 100644 +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -1486,7 +1486,6 @@ int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int); + void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *); + void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace); + void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace); +-void rxrpc_eaten_skb(struct sk_buff *, enum rxrpc_skb_trace); + void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace); + void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace); + void rxrpc_purge_queue(struct sk_buff_head *); +diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c +index fec59d9338b9..cc8f9dfa44e8 100644 +--- a/net/rxrpc/call_event.c ++++ b/net/rxrpc/call_event.c +@@ -332,7 +332,24 @@ bool rxrpc_input_call_event(struct rxrpc_call *call) + + saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK; + +- rxrpc_input_call_packet(call, skb); ++ if (sp->hdr.securityIndex != 0 && ++ skb_cloned(skb)) { ++ /* Unshare the packet so that it can be ++ * modified by in-place decryption. ++ */ ++ struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); ++ ++ if (nskb) { ++ rxrpc_new_skb(nskb, rxrpc_skb_new_unshared); ++ rxrpc_input_call_packet(call, nskb); ++ rxrpc_free_skb(nskb, rxrpc_skb_put_call_rx); ++ } else { ++ /* OOM - Drop the packet. */ ++ rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem); ++ } ++ } else { ++ rxrpc_input_call_packet(call, skb); ++ } + rxrpc_free_skb(skb, rxrpc_skb_put_call_rx); + did_receive = true; + } +diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c +index e939ecf417c4..6ff30afbc085 100644 +--- a/net/rxrpc/io_thread.c ++++ b/net/rxrpc/io_thread.c +@@ -192,13 +192,12 @@ static bool rxrpc_extract_abort(struct sk_buff *skb) + /* + * Process packets received on the local endpoint + */ +-static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) ++static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff *skb) + { + struct rxrpc_connection *conn; + struct sockaddr_rxrpc peer_srx; + struct rxrpc_skb_priv *sp; + struct rxrpc_peer *peer = NULL; +- struct sk_buff *skb = *_skb; + bool ret = false; + + skb_pull(skb, sizeof(struct udphdr)); +@@ -244,25 +243,6 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) + return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call); + if (sp->hdr.seq == 0) + return rxrpc_bad_message(skb, rxrpc_badmsg_zero_seq); +- +- /* Unshare the packet so that it can be modified for in-place +- * decryption. +- */ +- if (sp->hdr.securityIndex != 0) { +- skb = skb_unshare(skb, GFP_ATOMIC); +- if (!skb) { +- rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem); +- *_skb = NULL; +- return just_discard; +- } +- +- if (skb != *_skb) { +- rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare); +- *_skb = skb; +- rxrpc_new_skb(skb, rxrpc_skb_new_unshared); +- sp = rxrpc_skb(skb); +- } +- } + break; + + case RXRPC_PACKET_TYPE_CHALLENGE: +@@ -493,7 +473,7 @@ int rxrpc_io_thread(void *data) + switch (skb->mark) { + case RXRPC_SKB_MARK_PACKET: + skb->priority = 0; +- if (!rxrpc_input_packet(local, &skb)) ++ if (!rxrpc_input_packet(local, skb)) + rxrpc_reject_packet(local, skb); + trace_rxrpc_rx_done(skb->mark, skb->priority); + rxrpc_free_skb(skb, rxrpc_skb_put_input); +diff --git a/net/rxrpc/skbuff.c b/net/rxrpc/skbuff.c +index 3bcd6ee80396..e2169d1a14b5 100644 +--- a/net/rxrpc/skbuff.c ++++ b/net/rxrpc/skbuff.c +@@ -46,15 +46,6 @@ void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace why) + skb_get(skb); + } + +-/* +- * Note the dropping of a ref on a socket buffer by the core. +- */ +-void rxrpc_eaten_skb(struct sk_buff *skb, enum rxrpc_skb_trace why) +-{ +- int n = atomic_inc_return(&rxrpc_n_rx_skbs); +- trace_rxrpc_skb(skb, 0, n, why); +-} +- + /* + * Note the destruction of a socket buffer. + */ +-- +2.53.0 + diff --git a/patches/6.19/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch b/patches/6.19/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch new file mode 100644 index 0000000000..2ba346ed66 --- /dev/null +++ b/patches/6.19/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch @@ -0,0 +1,44 @@ +From 53e3b2bcd7d1a1fb428d0883a05b54bb0d366b82 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Thu, 23 Apr 2026 21:09:06 +0100 +Subject: [PATCH 3/8] rxrpc: Fix rxrpc_input_call_event() to only unshare DATA + packets + +Fix rxrpc_input_call_event() to only unshare DATA packets and not ACK, +ABORT, etc.. + +And with that, rxrpc_input_packet() doesn't need to take a pointer to the +pointer to the packet, so change that to just a pointer. + +Fixes: 1f2740150f90 ("rxrpc: Fix potential UAF after skb_unshare() failure") +Closes: https://sashiko.dev/#/patchset/20260422161438.2593376-4-dhowells@redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260423200909.3049438-2-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 55b2984c96c37f909bbfe8851f13152693951382) +--- + net/rxrpc/call_event.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c +index cc8f9dfa44e8..fdd683261226 100644 +--- a/net/rxrpc/call_event.c ++++ b/net/rxrpc/call_event.c +@@ -332,7 +332,8 @@ bool rxrpc_input_call_event(struct rxrpc_call *call) + + saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK; + +- if (sp->hdr.securityIndex != 0 && ++ if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA && ++ sp->hdr.securityIndex != 0 && + skb_cloned(skb)) { + /* Unshare the packet so that it can be + * modified by in-place decryption. +-- +2.53.0 + diff --git a/patches/6.19/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch b/patches/6.19/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch new file mode 100644 index 0000000000..188b816c27 --- /dev/null +++ b/patches/6.19/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch @@ -0,0 +1,72 @@ +From 94973b24d4136293be23603a914967747da0c6a7 Mon Sep 17 00:00:00 2001 +From: Alok Tiwari +Date: Wed, 8 Apr 2026 13:12:34 +0100 +Subject: [PATCH 4/8] rxrpc: Fix use of wrong skb when comparing queued RESP + challenge serial + +In rxrpc_post_response(), the code should be comparing the challenge serial +number from the cached response before deciding to switch to a newer +response, but looks at the newer packet private data instead, rendering the +comparison always false. + +Fix this by switching to look at the older packet. + +Fix further[1] to substitute the new packet in place of the old one if +newer and also to release whichever we don't use. + +Fixes: 5800b1cf3fd8 ("rxrpc: Allow CHALLENGEs to the passed to the app for a RESPONSE") +Signed-off-by: Alok Tiwari +Signed-off-by: David Howells +Reviewed-by: Jeffrey Altman +cc: Marc Dionne +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com [1] +Link: https://patch.msgid.link/20260408121252.2249051-7-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit b33f5741bb187db8ff32e8f5b96def77cc94dfca) +--- + include/trace/events/rxrpc.h | 1 + + net/rxrpc/conn_event.c | 5 +++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h +index 8a338f370de9..94f804ec8831 100644 +--- a/include/trace/events/rxrpc.h ++++ b/include/trace/events/rxrpc.h +@@ -183,6 +183,7 @@ + EM(rxrpc_skb_put_input, "PUT input ") \ + EM(rxrpc_skb_put_jumbo_subpacket, "PUT jumbo-sub") \ + EM(rxrpc_skb_put_oob, "PUT oob ") \ ++ EM(rxrpc_skb_put_old_response, "PUT old-resp ") \ + EM(rxrpc_skb_put_purge, "PUT purge ") \ + EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \ + EM(rxrpc_skb_put_response, "PUT response ") \ +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index 98ad9b51ca2c..c50cbfc5a313 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -557,11 +557,11 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb) + spin_lock_irq(&local->lock); + old = conn->tx_response; + if (old) { +- struct rxrpc_skb_priv *osp = rxrpc_skb(skb); ++ struct rxrpc_skb_priv *osp = rxrpc_skb(old); + + /* Always go with the response to the most recent challenge. */ + if (after(sp->resp.challenge_serial, osp->resp.challenge_serial)) +- conn->tx_response = old; ++ conn->tx_response = skb; + else + old = skb; + } else { +@@ -569,4 +569,5 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb) + } + spin_unlock_irq(&local->lock); + rxrpc_poke_conn(conn, rxrpc_conn_get_poke_response); ++ rxrpc_free_skb(old, rxrpc_skb_put_old_response); + } +-- +2.53.0 + diff --git a/patches/6.19/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch b/patches/6.19/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch new file mode 100644 index 0000000000..b524f4eafe --- /dev/null +++ b/patches/6.19/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch @@ -0,0 +1,79 @@ +From 662e6d8b63299d3c0d2a57bdf73e39210ea8a424 Mon Sep 17 00:00:00 2001 +From: Wang Jie +Date: Wed, 8 Apr 2026 13:12:48 +0100 +Subject: [PATCH 5/8] rxrpc: only handle RESPONSE during service challenge + +Only process RESPONSE packets while the service connection is still in +RXRPC_CONN_SERVICE_CHALLENGING. Check that state under state_lock before +running response verification and security initialization, then use a local +secured flag to decide whether to queue the secured-connection work after +the state transition. This keeps duplicate or late RESPONSE packets from +re-running the setup path and removes the unlocked post-transition state +test. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Jie Wang +Signed-off-by: Yang Yang +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260408121252.2249051-21-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit c43ffdcfdbb5567b1f143556df8a04b4eeea041c) +--- + net/rxrpc/conn_event.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index c50cbfc5a313..9a41ec708aeb 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -247,6 +247,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, + struct sk_buff *skb) + { + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); ++ bool secured = false; + int ret; + + if (conn->state == RXRPC_CONN_ABORTED) +@@ -262,6 +263,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, + return ret; + + case RXRPC_PACKET_TYPE_RESPONSE: ++ spin_lock_irq(&conn->state_lock); ++ if (conn->state != RXRPC_CONN_SERVICE_CHALLENGING) { ++ spin_unlock_irq(&conn->state_lock); ++ return 0; ++ } ++ spin_unlock_irq(&conn->state_lock); ++ + ret = conn->security->verify_response(conn, skb); + if (ret < 0) + return ret; +@@ -272,11 +280,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, + return ret; + + spin_lock_irq(&conn->state_lock); +- if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) ++ if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) { + conn->state = RXRPC_CONN_SERVICE; ++ secured = true; ++ } + spin_unlock_irq(&conn->state_lock); + +- if (conn->state == RXRPC_CONN_SERVICE) { ++ if (secured) { + /* Offload call state flipping to the I/O thread. As + * we've already received the packet, put it on the + * front of the queue. +-- +2.53.0 + diff --git a/patches/6.19/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch b/patches/6.19/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch new file mode 100644 index 0000000000..f779b500d9 --- /dev/null +++ b/patches/6.19/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch @@ -0,0 +1,79 @@ +From a7f61c028f5fda7e1da489288a36d632a61ace5a Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Wed, 22 Apr 2026 17:14:33 +0100 +Subject: [PATCH 6/8] rxrpc: Fix conn-level packet handling to unshare RESPONSE + packets + +The security operations that verify the RESPONSE packets decrypt bits of it +in place - however, the sk_buff may be shared with a packet sniffer, which +would lead to the sniffer seeing an apparently corrupt packet (actually +decrypted). + +Fix this by handing a copy of the packet off to the specific security +handler if the packet was cloned. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260422161438.2593376-5-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 24481a7f573305706054c59e275371f8d0fe919f) +--- + net/rxrpc/conn_event.c | 29 ++++++++++++++++++++++++++++- + 1 file changed, 28 insertions(+), 1 deletion(-) + +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index 9a41ec708aeb..aee977291d90 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -240,6 +240,33 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call) + rxrpc_notify_socket(call); + } + ++static int rxrpc_verify_response(struct rxrpc_connection *conn, ++ struct sk_buff *skb) ++{ ++ int ret; ++ ++ if (skb_cloned(skb)) { ++ /* Copy the packet if shared so that we can do in-place ++ * decryption. ++ */ ++ struct sk_buff *nskb = skb_copy(skb, GFP_NOFS); ++ ++ if (nskb) { ++ rxrpc_new_skb(nskb, rxrpc_skb_new_unshared); ++ ret = conn->security->verify_response(conn, nskb); ++ rxrpc_free_skb(nskb, rxrpc_skb_put_response_copy); ++ } else { ++ /* OOM - Drop the packet. */ ++ rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem); ++ ret = -ENOMEM; ++ } ++ } else { ++ ret = conn->security->verify_response(conn, skb); ++ } ++ ++ return ret; ++} ++ + /* + * connection-level Rx packet processor + */ +@@ -270,7 +297,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, + } + spin_unlock_irq(&conn->state_lock); + +- ret = conn->security->verify_response(conn, skb); ++ ret = rxrpc_verify_response(conn, skb); + if (ret < 0) + return ret; + +-- +2.53.0 + diff --git a/patches/6.19/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch b/patches/6.19/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch new file mode 100644 index 0000000000..26b74e266b --- /dev/null +++ b/patches/6.19/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch @@ -0,0 +1,76 @@ +From 98be347c5f2564c13fc8def0ecb2ed0cca54a11a Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Thu, 23 Apr 2026 21:09:07 +0100 +Subject: [PATCH 7/8] rxrpc: Fix re-decryption of RESPONSE packets + +If a RESPONSE packet gets a temporary failure during processing, it may end +up in a partially decrypted state - and then get requeued for a retry. + +Fix this by just discarding the packet; we will send another CHALLENGE +packet and thereby elicit a further response. Similarly, discard an +incoming CHALLENGE packet if we get an error whilst generating a RESPONSE; +the server will send another CHALLENGE. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Closes: https://sashiko.dev/#/patchset/20260422161438.2593376-4-dhowells@redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260423200909.3049438-3-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 0422e7a4883f25101903f3e8105c0808aa5f4ce9) +--- + include/trace/events/rxrpc.h | 1 - + net/rxrpc/conn_event.c | 14 ++------------ + 2 files changed, 2 insertions(+), 13 deletions(-) + +diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h +index 94f804ec8831..eb8150afd6df 100644 +--- a/include/trace/events/rxrpc.h ++++ b/include/trace/events/rxrpc.h +@@ -284,7 +284,6 @@ + EM(rxrpc_conn_put_unidle, "PUT unidle ") \ + EM(rxrpc_conn_put_work, "PUT work ") \ + EM(rxrpc_conn_queue_challenge, "QUE chall ") \ +- EM(rxrpc_conn_queue_retry_work, "QUE retry-wk") \ + EM(rxrpc_conn_queue_rx_work, "QUE rx-work ") \ + EM(rxrpc_conn_see_new_service_conn, "SEE new-svc ") \ + EM(rxrpc_conn_see_reap_service, "SEE reap-svc") \ +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index aee977291d90..a2130d25aaa9 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -389,7 +389,6 @@ void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force) + static void rxrpc_do_process_connection(struct rxrpc_connection *conn) + { + struct sk_buff *skb; +- int ret; + + if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events)) + rxrpc_secure_connection(conn); +@@ -398,17 +397,8 @@ static void rxrpc_do_process_connection(struct rxrpc_connection *conn) + * connection that each one has when we've finished with it */ + while ((skb = skb_dequeue(&conn->rx_queue))) { + rxrpc_see_skb(skb, rxrpc_skb_see_conn_work); +- ret = rxrpc_process_event(conn, skb); +- switch (ret) { +- case -ENOMEM: +- case -EAGAIN: +- skb_queue_head(&conn->rx_queue, skb); +- rxrpc_queue_conn(conn, rxrpc_conn_queue_retry_work); +- break; +- default: +- rxrpc_free_skb(skb, rxrpc_skb_put_conn_work); +- break; +- } ++ rxrpc_process_event(conn, skb); ++ rxrpc_free_skb(skb, rxrpc_skb_put_conn_work); + } + } + +-- +2.53.0 + diff --git a/patches/6.19/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch b/patches/6.19/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch new file mode 100644 index 0000000000..92d0c9dbc3 --- /dev/null +++ b/patches/6.19/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch @@ -0,0 +1,55 @@ +From 606cb2021745a1206f43a24b6c795c187e01df6f Mon Sep 17 00:00:00 2001 +From: Hyunwoo Kim +Date: Fri, 8 May 2026 15:42:28 +0900 +Subject: [PATCH 8/8 v2] rxrpc: Also unshare DATA/RESPONSE packets when paged + frags are present + +The DATA-packet handler in rxrpc_input_call_event() and the RESPONSE +handler in rxrpc_verify_response() copy the skb to a linear one before +calling into the security ops only when skb_cloned() is true. An skb +that is not cloned but still carries paged fragments (skb->data_len != 0) +falls through to the in-place decryption path, which binds the frag +pages directly into the AEAD/skcipher SGL via skb_to_sgvec(). + +Extend the gate so that any skb with non-linear data is also copied, +ensuring the security handler always operates on a fully linear skb. +The OOM/trace handling already in place is reused. + +Fixes: d0d5c0cd1e71 ("rxrpc: Use skb_unshare() rather than skb_cow_data()") +Cc: stable@vger.kernel.org +Signed-off-by: Hyunwoo Kim +Link: https://lore.kernel.org/netdev/af2ZMmJ4Oa0tscfC@v4bel/T/#t +--- + net/rxrpc/call_event.c | 2 +- + net/rxrpc/conn_event.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c +index fdd683261226..a6ad5ff6ec5f 100644 +--- a/net/rxrpc/call_event.c ++++ b/net/rxrpc/call_event.c +@@ -334,7 +334,7 @@ bool rxrpc_input_call_event(struct rxrpc_call *call) + + if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA && + sp->hdr.securityIndex != 0 && +- skb_cloned(skb)) { ++ (skb_cloned(skb) || skb_is_nonlinear(skb))) { + /* Unshare the packet so that it can be + * modified by in-place decryption. + */ +diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c +index a2130d25aaa9..632cbeff1f5d 100644 +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -245,7 +245,7 @@ static int rxrpc_verify_response(struct rxrpc_connection *conn, + { + int ret; + +- if (skb_cloned(skb)) { ++ if (skb_cloned(skb) || skb_is_nonlinear(skb)) { + /* Copy the packet if shared so that we can do in-place + * decryption. + */ +-- +2.53.0 + diff --git a/pkg/arch/kernel/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch b/pkg/arch/kernel/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch new file mode 120000 index 0000000000..cf72ae8f88 --- /dev/null +++ b/pkg/arch/kernel/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch @@ -0,0 +1 @@ +../../../patches/6.19/0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch b/pkg/arch/kernel/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch new file mode 120000 index 0000000000..22d89dfcc6 --- /dev/null +++ b/pkg/arch/kernel/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch @@ -0,0 +1 @@ +../../../patches/6.19/0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch b/pkg/arch/kernel/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch new file mode 120000 index 0000000000..2600ee0a62 --- /dev/null +++ b/pkg/arch/kernel/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch @@ -0,0 +1 @@ +../../../patches/6.19/0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch b/pkg/arch/kernel/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch new file mode 120000 index 0000000000..689c431b66 --- /dev/null +++ b/pkg/arch/kernel/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch @@ -0,0 +1 @@ +../../../patches/6.19/0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch b/pkg/arch/kernel/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch new file mode 120000 index 0000000000..2d95b72994 --- /dev/null +++ b/pkg/arch/kernel/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch @@ -0,0 +1 @@ +../../../patches/6.19/0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch b/pkg/arch/kernel/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch new file mode 120000 index 0000000000..f75d7515d7 --- /dev/null +++ b/pkg/arch/kernel/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch @@ -0,0 +1 @@ +../../../patches/6.19/0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch b/pkg/arch/kernel/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch new file mode 120000 index 0000000000..02666fe7c9 --- /dev/null +++ b/pkg/arch/kernel/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch @@ -0,0 +1 @@ +../../../patches/6.19/0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch \ No newline at end of file diff --git a/pkg/arch/kernel/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch b/pkg/arch/kernel/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch new file mode 120000 index 0000000000..5ef0cec577 --- /dev/null +++ b/pkg/arch/kernel/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch @@ -0,0 +1 @@ +../../../patches/6.19/0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch \ No newline at end of file diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index ecda70f269..b1aece5180 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -4,7 +4,7 @@ pkgbase=linux-surface pkgver=6.19.8.arch1 -pkgrel=2 +pkgrel=3 pkgdesc='Linux' _shortver=${pkgver%.*} _fullver=${pkgver%.*}-${pkgver##*.} @@ -58,6 +58,14 @@ source=( 0014-amd-gpio.patch 0015-rtc.patch 0016-hid-surface.patch + 0017-dirtyfrag-xfrm-esp-avoid-in-place-decrypt-on-shared-skb-frags.patch + 0018-dirtyfrag-rxrpc-Fix-potential-UAF-after-skb_unshare-failure.patch + 0019-dirtyfrag-rxrpc-Fix-rxrpc_input_call_event-to-only-unshare-DAT.patch + 0020-dirtyfrag-rxrpc-Fix-use-of-wrong-skb-when-comparing-queued-RES.patch + 0021-dirtyfrag-rxrpc-only-handle-RESPONSE-during-service-challenge.patch + 0022-dirtyfrag-rxrpc-Fix-conn-level-packet-handling-to-unshare-RESP.patch + 0023-dirtyfrag-rxrpc-Fix-re-decryption-of-RESPONSE-packets.patch + 0024-dirtyfrag-rxrpc-Also-unshare-DATA-RESPONSE-packets-when-paged-.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds @@ -83,7 +91,15 @@ sha256sums=('4d1e35866e69aaef26812c1cc5651936faa5e360b5ef6a19c28fb19b6848ab4b' 'dbaddf5ed1ec7aec515867facd17a09e083289eb4185b3af4f3bc1d6c9bd1ad7' '1d703ad95120df846d77b0c5338af1829119e2bfcac258ebedf0145ba02e22f3' '76b91256a525c4f626802b5ad29ddb1a9477bc90001c9ea8c469ae77d07593fc' - '32b91e80ddc124dc7f31bbde65fcb18fa7a7f194f953ccfc8f14d630aac4ddc4') + '32b91e80ddc124dc7f31bbde65fcb18fa7a7f194f953ccfc8f14d630aac4ddc4' + 'fac88ee98cfdfe25e408410e32182d1333ad70daf0d7393616062bc742ab16a9' + '49720fcc7dc3985a23f28690bf8617782e73c164f5b1faa5baad64d2914470cc' + '07daf409a43ae3eea6d3a7f0faa27de273dd1036220ebaf06327423508d154b8' + '293baa7fa7ea5a6c0eca70865242478640b02e45b336e541e7c2aca502d20ae8' + '780f99c5da46b2afacca860aa711342c654d66dbf8aa9a78575ec9061f5591e4' + 'b8de9f82cf402f52c65a777b3944a153a47310a13ec8629a3b9f907d792bfbe6' + '0b7785bfb9b00326f5575e85f869c19e40a4d829267c7aded75df6bd532b622d' + '4fee526034c01a578577ea85a569ace805fbaf66e68d6bf4cab030aabc007d51') export KBUILD_BUILD_HOST=archlinux diff --git a/pkg/debian/kernel/version.conf b/pkg/debian/kernel/version.conf index 8687a73b57..1b504567ab 100644 --- a/pkg/debian/kernel/version.conf +++ b/pkg/debian/kernel/version.conf @@ -1,3 +1,3 @@ KERNEL_VERSION="6.19.8" -KERNEL_REVISION="2" +KERNEL_REVISION="3" KERNEL_LOCALVERSION="-surface" diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py index fde85dae98..28e48dc40a 100755 --- a/pkg/fedora/kernel-surface/build-linux-surface.py +++ b/pkg/fedora/kernel-surface/build-linux-surface.py @@ -25,7 +25,7 @@ ## The release number of the modified kernel package. ## e.g. 300 for kernel-6.3.1-300.fc38.foo ## -PACKAGE_RELEASE = "2" +PACKAGE_RELEASE = "3" ## ## Build options for configuring which parts of the kernel package are enabled. From bf1921fc63f33d03a007fb38c4f88ff7e7bc1a55 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 9 May 2026 12:40:00 +0200 Subject: [PATCH 236/236] pkg: arch: Fix wrong sha256sum for surface.config --- pkg/arch/kernel/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index b1aece5180..62f9d4a64d 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -74,7 +74,7 @@ validpgpkeys=( ) sha256sums=('4d1e35866e69aaef26812c1cc5651936faa5e360b5ef6a19c28fb19b6848ab4b' 'd0ce1ee11ca0bc6a817c3c17a2651076409bd9fd6c0ab9e744aae2131ab654ce' - '645003a31150560e2cd367a25c66b9957a7fefed37053c9f89960a487af86af8' + '3732912dbdf6419df696eec4c40d8edfad90a529e9cfe09b365c2b558690f9b7' '008e37de7e6cf8b9479ef0f0f425a25092646e85d741aedd056e5ff3e1096361' '5113eaf632692852082972ff881321428b060efd4ff0177c2ce3c72c64ad76e7' 'dbad1231a9a0a2bcf4f6567149e5b86f82f4bb29a3b3fa91543b1996e66353f4'